Skip to content

fix: received large images show 'not available' (array-format extraction corruption) - #1211

Merged
torlando-tech merged 1 commit into
mainfrom
fix/received-image-array-extraction
Oct 22, 2026
Merged

torlando-tech merged 1 commit into
mainfrom
fix/received-image-array-extraction

Conversation

@torlando-tech

Copy link
Copy Markdown
Owner

Problem

Receiving an image attachment sometimes renders "image not available" (user-reported, most visible with Columba-iOS senders).

Every Columba sender puts LXMF field 6 on the wire as [format, bytes] (NativeMessageSender.kt:145, Columba-iOS RnsLxmf; the iOS interop test pins the shape: "the on-wire shape is [format_str, bytes]"), and both Android backends serialize a received image field as the JSON array ["jpg", "<hex>"].

When such a field exceeded the 500 KB attachment-extraction threshold, ConversationRepository.extractLargeAttachments took the generic branch: it stored the whole array string ["jpg","ffd8..."] to disk and replaced the field with a bare {"_file_ref": path} object. MessageMapper.loadImageBytes hex-decodes file-ref payloads, so it tried to hex-decode ["jpg",... → hexStringToByteArray threw → null → the UI showed "not available". hasImageField still returned true (bare file ref), so the bubble appeared with no image.

Images below the threshold (LOW/MEDIUM presets, small photos) stayed inline and decoded fine — hence "sometimes". Audio (field 7) already had special handling; image (field 6) was missed.

Fix

  • Extraction (ConversationRepository): new extractImageAttachmentForStorage mirrors the audio path — writes only the hex payload to disk and keeps the array shape: ["jpg", {"_file_ref": path}].
  • Loader (MessageMapper.loadImageBytes): resolves a _file_ref nested in the array, and unwrapArrayPayload recovers payloads written by the old code (whole-array files), so already-received "not available" messages heal on next display without re-download.
  • Bubble gating: hasImageField in MessageMapper and MessagingViewModel recognize the array+file-ref shape.

Tests

  • ConversationRepositoryImageExtractionTest (data): red-before/passing-after repro — large array-format field 6 extracts to pure hex with array shape kept; hex-string format regression guard; small arrays untouched.
  • MessageMapperTest (app): inline array decode, nested file-ref resolution, legacy whole-array recovery, staging fallback, hasImageAttachment for the new shape.
  • Full :data suite, MessageMapperTest, MessagingViewModelTest, and :app:detekt/:data:detekt all pass.

Every Columba sender puts LXMF field 6 on the wire as [format, bytes],
and both backends serialize a received image as the JSON array
["jpg", "<hex>"]. When such a field exceeded the 500KB extraction
threshold, the generic path stored the whole array string to disk and
replaced the field with a bare {"_file_ref": path} object. The message
mapper hex-decodes file-ref payloads, so it tried to hex-decode
["jpg",... , failed, and the bubble rendered "image not available".
Images under the threshold (LOW/MEDIUM presets) stayed inline and
worked, which is why the bug looked intermittent.

Mirror the audio (field 7) handling: extraction now writes only the hex
payload and keeps the array shape as ["jpg", {"_file_ref": path}]. The
loader resolves a file ref nested in the array, and file-ref payloads
that contain a whole array string (written by the old code) are unwrapped
so already-received "not available" messages heal without re-download.
hasImageField in MessageMapper and MessagingViewModel recognize the new
shape.
@greptile-apps

greptile-apps Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable new issues were found.

Summary

Fixes large received images by saving only their hex payload and preserving the image array.

  • Large received images load from their saved payload.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Received image array] --> B{Large hex payload?}
  B -->|No| C[Keep image inline]
  B -->|Yes| D[Save hex payload to disk]
  D --> E[Keep format and nested file reference]
  E --> F[loadImageBytes]
  G[Legacy whole-array file] --> H[unwrapArrayPayload]
  H --> F
  F --> I[Decode image bytes]
Loading

Reviews (2) · Last reviewed commit: "fix(data): keep array shape when extract..." · Reviewed by Greptile

@torlando-tech

Copy link
Copy Markdown
Owner Author

@greptile review

@codecov

codecov Bot commented Oct 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@torlando-tech
torlando-tech merged commit efecfdd into main Oct 22, 2026
15 checks passed
@torlando-tech
torlando-tech deleted the fix/received-image-array-extraction branch October 22, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant