fix(web): guard empty canvas blob + fall back to original file on upload (BUNYIP-408) #402
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/BUNYIP-408-avatar-empty-blob"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Real root cause
The upload error is the bunyip-web message "The selected file is empty." (
read_avatar_uploadwhenbytes.is_empty()). So the upload never reached bunyip-api - the client was sending a 0-byte file. My earlier stale-API theory was wrong; this is a client bug.Why: the re-encode used
canvas.toBlob('image/webp', ...), and some browsers return an empty (0-byte) Blob there instead ofnull. An empty Blob is truthy, so the oldif(!blob)guard let it through, and the empty part uploaded → 400.Fix (bulletproof)
blob.size === 0(or a null blob, or any processing error) as "re-encode failed".upload()also refuses a zero-size payload outright with a clear inline error, so an empty request can never round-trip again.Verification
node --check.just check-containergreen: fmt + clippy-D warnings+ all test binaries (116 web tests).Follow-up to #401 (data:-URL preview) and #400 (inline CSS). With this, the change-photo flow uploads real bytes on every browser.
🤖 Generated with Claude Code
Real cause of the upload 400, from the actual server message "The selected file is empty": the client was uploading a 0-byte file. The re-encode used `canvas.toBlob('image/webp')`, and some browsers return an EMPTY (0-byte) Blob there rather than null. An empty Blob is truthy, so the old `if(!blob)` guard passed it straight through and the empty part uploaded, which bunyip-web's `read_avatar_upload` rejects as empty (400). This is a client bug, not the stale-API theory from the previous commit - the upload never reached the API. Two guards make it bulletproof: - Encode to JPEG (already in this branch) instead of WebP - reliable canvas support - and treat `blob.size === 0` (or a null blob, or any processing error) as "re-encode failed". - On that failure, upload the ORIGINAL validated file instead. The API accepts png/jpeg/webp/gif and re-validates, so the user's pick still uploads even if canvas re-encoding is unavailable; only the client-side downscale is skipped in that path. - `upload()` also refuses a zero-size payload outright with a clear inline error rather than round-tripping an empty request. JS validated with `node --check`; `just check-container` green (116 web tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5dcYueNHByRnWJDYoDX1W