Repository navigation
fix(mobile): send photos, files and pasted images again - #2444
Conversation
The app's global fetch is expo/fetch (Expo SDK 58). It sends a Blob body with the Blob's own type as Content-Type, overriding the octet-stream header the upload set, so the Host turned every photo upload away and the message stayed "Not sent". Uploads now go out as an octet-stream Blob. On Android expo/fetch cannot open the data: URI a pasted image uses, so the paste is read back from a cache file. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PKDsNqHnFbKdw4gcR9K5Yk
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 20 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PKDsNqHnFbKdw4gcR9K5Yk
|
iOS 27 Simulator at ca9c7a8: all 6 pass. This ran on a Release Simulator build, with the QA Host on main a32b62b. Every send showed as sent, never "Not sent". The Host's channel messages confirmed each one arrived, and the Bot replied describing each image.
A nit that doesn't block: a HEIC photo picked with + → Photos shows as a file chip in the app instead of an image preview. The Bot still read it. Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Android phone result: PASS (Xiaomi, Android 16 / HyperOS 3, release build from main c67d231 with this PR merged, isolated QA Host) Screenshots: 2444-android/phone (commit 090d949)
The Bot described the content of each image in its reply, which confirms that every image reached it. Generated by Claude Code |






Requested by Vain · project thread
Why the change
The phone app could not send any attachment: photos shared from Photos, photos picked with + → Photos, and pasted images all stayed on "Not sent · Tap to retry".
Issue / Discussion: Refs #2422 (comment)
Special things to note
fetchisexpo/fetch. When the body is aBlob,expo/fetchsends the Blob's own type asContent-Typeand drops the header the caller set (normalizeBodyInitAsync→overrideHeadersinexpo/src/winter/fetch). A photo read fromfile://is animage/jpegBlob, so the upload went out asimage/jpeg. The device gateway only routesapplication/octet-streamPOSTs to the attachment handler, so the upload never reached it,upload()threw, andchannelSendwas never called. A probe device sending real octet-stream succeeds, which matches the QA finding. This was not caused by fix(mobile): Android fixes from the real-device QA of #2364, #2380 and #2401 #2422, feat(mobile): share text, links and files to a Bot from any app #2401 or feat(mobile): chat QoL — pull up to type, paste images, double-tap 👍, peek at chats #2364. No recent mobile change touchedupload()ordeliver().upload()re-wraps the Blob asnew Blob([data], { type: 'application/octet-stream' }), so the header that goes on the wire is octet-stream whatever fetch does. The same JS runs on iOS and Android.expo/fetchonly accepts http(s) andfile://URLs. It cannot open thedata:URI a clipboard image uses, so a pasted image could not even be read.fromClipboardImagenow writes the base64 data to a cache file, reads that file, and deletes it.expo/fetchplus the real gateway, sending the Blob type asContent-Typeand refusing anything that is not octet-stream. The new testuploads a typed photo as octet-stream so the Host accepts itand the two existing upload tests fail without the fix and pass with it. A new clipboard test checks that a paste is read from a cache file, not from thedata:URI.pnpm vitest run apps/mobilegives 982 passed and 9 skipped, and the mobile typecheck passes.image/pngcontent type straight to/botharness-device/api/botharness/attachment/uploadand got 502host-session-unavailable. An octet-stream upload got 200 and an attachment back.attachments.live.test.tspasses against that Host.Change outline
apps/mobile/src/host/client.ts: the upload body is always an octet-stream Blob.apps/mobile/src/host/pick-files.ts: a pasteddata:image is read through a temporary cache file.apps/mobile/test/fake-host.ts: the upload content type now comes from the Blob type, asexpo/fetchsends it, and non-octet-stream uploads are refused.conversation.test.ts,clipboard-image.test.tsx, plus anexpo-file-systemmock inincoming-share.test.ts.No UI changes.
Generated by Claude Code