fix(gemini): type mp4/mov/webm uploads so Gemini actually receives them - #332
fix(gemini): type mp4/mov/webm uploads so Gemini actually receives them#332mkubenka wants to merge 1 commit into
Conversation
dcab67e to
a8591ed
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Gemini silently discards uploads it cannot type. Any extension missing from
GEMINI_UPLOAD_MIME_TYPES fell back to `application/octet-stream`, so the run
reported the file as attached (`files=1`) while the model answered as though
nothing had been sent.
That made video look unsupported when the upload path itself was fine.
Declaring `video/mp4` for the same MP4 works immediately: Gemini describes
the footage and quotes on-screen text.
Add only the three formats confirmed against the live endpoint, and pull the
lookup into an exported `resolveGeminiUploadMimeType` so it can be tested.
Probed each candidate with a sentinel prompt that distinguishes "received"
from "actually viewable":
.mp4 .mov .webm viewable - describe people, clothing and on-screen text
.avi received but not viewable; only echoed container metadata
.m4v dropped, despite identical bytes to a working .mp4 and
the same declared video/mp4 - the endpoint gates on the
extension too
.mkv .3gp .heic Gemini returns an error
.wav .mp3 .m4a never delivered, with audio/mpeg, audio/mp3, audio/wav
or audio/x-wav
.txt never delivered, with text/plain or text/md
So audio and plain text are not supported by this endpoint at all, and the
accepted set cannot be extrapolated from the Gemini API's documented formats.
Mapping them would advertise support that does not exist.
Note the 1 MB DEFAULT_MAX_FILE_SIZE_BYTES still applies; video generally
needs `--max-file-size-bytes` / ORACLE_MAX_FILE_SIZE_BYTES.
a8591ed to
4ddc53c
Compare
Manual hardened port of upstream PR steipete#332 (a8591ed), with end-to-end multipart and f.req coverage. Co-authored-by: Michal Kubenka <mkubenka@gmail.com>
|
Codex review: needs changes before merge. Reviewed July 31, 2026, 5:40 PM ET / 21:40 UTC. ClawSweeper reviewWhat this changesThis PR maps Merge readinessThe Gemini video-upload bug remains on current Priority: P1 Review scores
Verification
How this fits togetherOracle’s Gemini web client reads CLI file attachments, uploads each file to Gemini, then includes the declared MIME type in the generated chat request. A missing extension mapping currently falls back to flowchart LR
A[CLI file attachment] --> B[Gemini web executor]
B --> C[Gemini upload client]
C --> D[Extension to MIME lookup]
D --> E[Gemini upload request]
E --> F[Chat request with attachment metadata]
F --> G[Gemini model response]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Keep the three validated video mappings and focused resolver tests, then move the release note into the current Do we have a high-confidence way to reproduce the issue? Yes—current source deterministically sends these video extensions through the octet-stream fallback, and the PR supplies a concrete authenticated Gemini browser command plus before/after live output. A reviewer can reproduce with a supported video fixture under the 1 MB limit or with an explicit higher file-size setting. Is this the best way to solve the issue? No—not until the changelog hunk is moved. The MIME mappings, resolver extraction, and fallback-preserving tests are the narrowest maintainable repair, but the release note must target Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 68b8c51b0ee0. LabelsLabel justifications:
EvidenceAcceptance criteria:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (11 earlier review cycles; latest 8 shown)
|
The bug
GEMINI_UPLOAD_MIME_TYPEScovers only images and PDF. Everything else falls through toapplication/octet-stream, and Gemini silently discards uploads it cannot type.The failure is invisible from the outside, which is what makes it expensive:
The upload succeeds, the payload is built,
files=1is printed — and the model gets nothing. Reading the source reinforces the wrong conclusion, because the upload path genuinely is complete and correct. Only the MIME label is wrong.Declaring
video/mp4makes the same file work on the first attempt:The change
Adds exactly three entries —
.mp4,.mov,.webm— and extracts the lookup into an exportedresolveGeminiUploadMimeType()so it is unit-testable. No behaviour change for currently-mapped types; theapplication/octet-streamfallback is preserved.Why only three
I first wrote a much larger table from the Gemini API's documented formats, then probed each candidate against the live endpoint with a sentinel prompt separating "received" from "actually viewable". Most of it was wrong:
.mp4.mov.webm.aviLavf62.3.100).m4v.mp4and the same declaredvideo/mp4.mkv.3gp.heic.wav.mp3.m4aaudio/mpeg,audio/mp3,audio/wav,audio/x-wav.txttext/plainandtext/mdTwo conclusions worth recording:
.m4vcase is the proof: same bytes, samevideo/mp4, still dropped. So this table cannot be extrapolated from the Gemini API docs — each entry needs probing.I have kept the entries to what I verified. If you have a broader whitelist from the web app, more can be added safely.
Verification
Against
gemini-3.1-pro:NO VIDEO RECEIVED; after: accurate scene description plus verbatim on-screen subtitles, cross-checked against frames read locally.scale=640:-2,fps=8,crf 32). Answers to timestamp-specific questions matched an independently produced OCR transcript, including subtitles at 5:00 and 5:48 and both speakers' names.Checks:
vitest(5 new tests plus existingtests/gemini.test.ts— 15 passing),tsc --noEmit,oxfmt --check,oxlint.Notes for the maintainer
DEFAULT_MAX_FILE_SIZE_BYTESstill applies, so video realistically needs--max-file-size-bytes/ORACLE_MAX_FILE_SIZE_BYTES. Left alone as a separate policy decision.uploadGeminiFile()reads the whole file into a Buffer→Blob, so large media will exhaust the heap. Chunking is the practical answer; out of scope here.application/octet-streamarguably deserves a warning, since the current behaviour reports success while the model receives nothing — that is what made video look impossible rather than merely broken. There is no logger plumbed intoclient.ts's upload path, so I kept this PR to the data fix. Happy to follow up if you want the warning.