fix(media): m4a/AAC audio files from non-Apple sources are misidentified as video/mp4 and excluded from audio workflows#111177
Conversation
…tified as video/mp4
|
Codex review: needs maintainer review before merge. Reviewed July 20, 2026, 1:13 AM ET / 05:13 UTC. Summary PR surface: Source +3, Tests +48. Total +51 across 2 files. Reproducibility: yes. at source level: current main prioritizes Review metrics: none identified. Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the narrow M4A hint rescue after aligning the title and PR narrative with the final code: preserve M4A transport or filename hints for ambiguous ISO-BMFF bytes, while continuing to trust contradictory ISO-BMFF bytes over Do we have a high-confidence way to reproduce the issue? Yes at source level: current main prioritizes Is this the best way to solve the issue? Yes for the M4A regression: extending the existing ambiguous-container exception is narrower and safer than broadly trusting all audio headers over sniffed container bytes. The proposed AAC wording is not the best description because the final regression test intentionally keeps contradictory AGENTS.md: unclear because the file could not be read completely. Codex review notes: model internal, reasoning high; reviewed against 8f9e42f2a947. Label changesLabel justifications:
Evidence reviewedPR surface: Source +3, Tests +48. Total +51 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (1 earlier review cycle)
|
Co-authored-by: 潘晓波0668000512 <[email protected]>
|
Merged via squash.
|
…ied as video/mp4 and excluded from audio workflows (openclaw#111177) * fix(media): preserve audio hints for isom-brand m4a/AAC files misidentified as video/mp4 * fix(media): correct ambiguous M4A aliases Co-authored-by: 潘晓波0668000512 <[email protected]> --------- Co-authored-by: Peter Steinberger <[email protected]>
What Problem This Solves
Fixes an issue where non-Apple m4a/AAC audio files (Android voice recordings, ffmpeg-transcoded audio, Telegram/Signal voice messages) are misidentified as
video/mp4by the MIME detection pipeline, causing them to be silently excluded from audio-only workflows.The root cause is that
file-type(the npm dependency that sniffs magic bytes) detects ISO-BMFF containers with the "isom" or "mp42" ftyp brand asvideo/mp4regardless of content. Only Apple-authored m4a files use the "M4A " brand, whichfile-typecorrectly reports asaudio/mp4. The existing ambiguous-container rescue only coversaudio/mp4andaudio/webm— three real-world audio hint aliases and the file-extension-only case were left unprotected.Concrete user impact: voice message received via Telegram with Content-Type
audio/x-m4aoraudio/m4a→ stored with contentTypevideo/mp4→hasAudiocheck inbot-message-context.body.tsfails → no preflight transcription;selectAttachments("audio")filters it out viakindFromMimerouting it to video capability → user message is silently unhandled.Why This Change Was Made
Three
audio/*aliases (audio/x-m4a,audio/m4a,audio/aac) are added to the existingAMBIGUOUS_VIDEO_MIME_BY_AUDIO_MIMEmap, which rescues audio hints whenfile-typereturns one of the ambiguous container MIMEs (video/mp4,video/webm). These are aliases acknowledged by the repo's ownvoiceCompatMimeslist insrc/media/audio.ts.Additionally, the audioContainerHint search now falls back to the extension-derived MIME after transport-header-based hints. Without this, a bare
.m4afile with noContent-Typeheader producesvideo/mp4because onlymimeHints(transport headers) were consulted — the independently-computedextMimewas excluded from the rescue.The fix is bounded: it only changes what alias strings trigger the existing rescue when
file-typereturnsvideo/mp4. Genuine video files (.mp4extension,video/mp4header,.mp4extension without header) continue to returnvideo/mp4unchanged.User Impact
Voice messages from Android/ffmpeg-produced m4a files, AAC audio, and m4a files without a Content-Type header are now correctly identified as audio. They follow the audio path for storage, attachment selection, and preflight transcription — matching the existing behavior for Apple-authored "M4A "-brand m4a files.
Evidence
Live behavior proof (production
detectMime, isom-brand buffer)Driver: the production
detectMimefunction frompackages/media-core/src/mime.tsis called with a 28-byte isom-brand ftyp box buffer (the common ffmpeg/Android-produced m4a format) and real-world header/filename combinations.Before (current main) — 3 audio hint aliases and the ext-only case all return
video/mp4:After (this patch) — all audio cases return their expected audio MIME:
Regression coverage
packages/media-core/src/mime.test.ts(2 new): isom-brand buffer +audio/x-m4aheader preserves the audio hint; isom-brand buffer + bare.m4afilename (no header) rescues via extension.video/mp4; the rescue map lacks the alias; the extMime fallback is absent). 140 existing tests pass unchanged.node scripts/run-vitest.mjs packages/media-core/src/mime.test.ts→ 142 passed.git diff --checkclean.Sibling-surface context
The existing
audio/mp4andaudio/webmrescue in the same map was added in the original ambiguous-container fix and is pinned by tests atmime.test.ts:199-228. The three added aliases follow the same contract. Themedia.store.tscallers consumedetectMime's return value directly;kindFromMimeandisAudioFileNamederive their results from this return value. No config, schema, or storage migration is needed.