Skip to content

Image uploads corrupted on read due to simple-array comma-splitting base64 data URLs #1075

Description

@plansombl

Description

Every post that contains at least one image is silently corrupted the moment it is read back from the database. The root cause is that TypeORM's simple-array column type stores arrays by naively joining values with a comma (value.join(",")) and reads them back by splitting on comma (value.split(",")) — with no escaping whatsoever.

Base64 data URLs produced by FileReader.readAsDataURL() always contain a literal comma in their MIME prefix (e.g. data:image/png;base64,iVBORw0KGgo...). This comma is indistinguishable from simple-array's delimiter, so the stored string is always parsed incorrectly on read.

Single-image post

Stored fine (nothing to join), but .split(",") still fires unconditionally on read, breaking data:image/png;base64,AAAA... into two entries:

  • data:image/png;base64 — a truncated, invalid data URL with no payload
  • AAAA... — a bare base64 string with no data: prefix, which the browser treats as a relative URL, not an image

Multi-image post

The join-separator comma and each image's own internal comma become completely indistinguishable. Images interleave and split at wrong boundaries, corrupting the entire set.

This is very likely the root cause of the "flying stars / meteor shower" rendering artefacts previously reported — corrupted/partial image decodes rather than someone else's real photos.

Steps to reproduce

  1. Create a post and attach one or more images via the upload flow (post/+page.svelte)
  2. Save the post
  3. Navigate to the post grid / open the post detail
  4. Observe that images render as broken fragments, garbled pieces, or show browser image-load errors

Expected behavior

Uploaded images should be stored and retrieved without corruption. The full, valid base64 data URL should be recovered exactly as it was before storage, and images should render correctly in the post grid and post modal.

Current workaround

A frontend bandage — pairAndJoinChunks — exists in both Post.svelte (lines 32–55) and PostModal.svelte (line 45). It takes the corrupted flat array and re-pairs elements two-at-a-time, rejoining [prefix, payload] back into prefix,payload. This partially recovers single-image posts but remains brittle for multi-image posts where additional internal commas cause further mis-splits.

Proposed fix

Switch the column encoding from simple-array to simple-json (uses JSON.stringify / JSON.parse), which correctly escapes all internal characters including commas.

Both simple-array and simple-json compile down to a plain Postgres text column (confirmed by the original migration SQL — "images" text), so no schema migration is required.

Impact on existing data

Existing rows were stored with the old comma-joined format. Reading them with a JSON.parse decoder will throw a parse error rather than silently returning garbage. Old corrupted rows should be audited and either cleaned up or null-ed out before the fix is deployed, as the original image data cannot be reliably reconstructed from the corrupted fragments.

Steps

  1. Change the images column decorator from simple-array to simple-json in the relevant TypeORM entity
  2. Remove the pairAndJoinChunks workaround from Post.svelte and PostModal.svelte
  3. Handle/migrate (or purge) existing corrupted rows to prevent JSON parse errors at runtime
  4. Verify with a new post containing multiple images that all images are stored and displayed correctly

Supporting Media

N/A

Desktop

  • Device: N/A (server-side / DB layer bug)
  • OS: N/A
  • Browser: N/A
  • Version: N/A

Additional Context

  • Corruption affects every single post with at least one image — no posts are safe under the current encoding
  • If real users are onboarded before this is fixed, their uploaded images will be permanently unrecoverable
  • The fix is low-risk (no SQL schema change needed) but requires careful handling of already-corrupted rows in the DB

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority - 1Really important bug. App is broken, major functionality is unusable

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions