Skip to content

Fix: keep the uploaded file extension when transcribing#903

Open
e3o8o wants to merge 1 commit into
jamiepine:mainfrom
e3o8o:fix/transcribe-keeps-uploaded-extension
Open

Fix: keep the uploaded file extension when transcribing#903
e3o8o wants to merge 1 commit into
jamiepine:mainfrom
e3o8o:fix/transcribe-keeps-uploaded-extension

Conversation

@e3o8o

@e3o8o e3o8o commented Jul 15, 2026

Copy link
Copy Markdown

The bug

POST /transcribe writes every upload to a temp file named .wav, whatever the file actually is:

with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:

load_audio calls librosa.load, which picks its decoder from the extension. So an .m4a (or .mp3, .flac, .ogg) upload is handed to the wav decoder and dies:

{"detail":"could not open/decode file"}

The formats work everywhere else in the app, so this reads as "Voicebox cannot transcribe my recording" rather than "the temp file was misnamed". I hit it trying to transcribe an .m4a voice memo to use as a cloning reference.

The fix

profiles.py already solves exactly this for voice samples (lines 161-165): keep the uploaded extension when it is one of the audio types accepted, and fall back to .wav otherwise. This applies the same approach, with the same set, to /transcribe.

The fallback matters: an unknown or missing extension still becomes .wav, so today's behaviour is unchanged for anything that already worked, and an unexpected filename can never inject an arbitrary suffix.

Verification

The strongest evidence is that your own code already proves it. POST /profiles/{id}/samples keeps the uploaded extension, POST /transcribe does not, and they share load_audio. Same server, same file:

  • the .m4a posted to /profiles/{id}/samples200, decoded and transcoded to wav
  • the same .m4a posted to /transcribecould not open/decode file
  • the same audio converted to wav and posted to /transcribe200, transcribed fine

So the only difference between the path that works and the path that fails is the temp file's name.

I also checked the suffix selection across the cases that matter: Sepa.m4a.m4a, clip.MP3.mp3 (case-insensitive), noext.wav, evil.exe.wav, and empty/None filenames → .wav.

Tested against v0.3.x on macOS (MLX). I could not run the patched server itself, since my system Python does not have the backend's dependencies and I was testing against the bundled voicebox-server binary, so the end-to-end confirmation above is on the shipped build rather than this patch. The change is small enough to read, but worth saying plainly.

One thing I deliberately did not do

That extension set now exists in four places, and three of them disagree:

Where Set
routes/generations.py:25 no .opus
routes/profiles.py:161 has .opus
services/captures.py:75 no .aac, no .opus
routes/transcription.py (this PR) copied from profiles.py

Unifying them would change which formats three unrelated endpoints accept, which felt like the wrong thing to smuggle into a bug fix. Happy to send that as a separate PR if you want it, or to point this one at a shared constant instead if you would rather it not add a fourth copy.

Unrelated, while I was in here

whisper-turbo reliably 500s on MLX with There is no Stream(gpu, 2) in current thread, and can take the process down; base and small work. I can reproduce it consistently but do not understand the MLX threading here well enough to propose a fix, so I have left it out rather than guess. Happy to file it as an issue with the reproduction if useful.

Summary by CodeRabbit

  • Bug Fixes
    • Improved audio transcription compatibility by preserving supported uploaded audio file extensions.
    • Added a safe fallback to WAV when an extension is missing or unsupported.

/transcribe wrote every upload to a temp file named .wav regardless of its
real format. librosa picks its decoder from the extension, so any non-wav
upload failed with "could not open/decode file" even though the format is
one the app handles elsewhere.

profiles.py already solves this for voice samples by keeping the uploaded
extension when it is one of the audio types it accepts, and falling back to
.wav otherwise. Same approach here, same set. The fallback means an unknown
or missing extension behaves exactly as it does today.
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 53c35f65-75ed-45b3-8879-59a5a1c2859e

📥 Commits

Reviewing files that changed from the base of the PR and between f2cf2a7 and 8e84352.

📒 Files selected for processing (1)
  • backend/routes/transcription.py

📝 Walkthrough

Walkthrough

The transcription endpoint adds an audio-extension whitelist and uses approved uploaded extensions for temporary files, defaulting to .wav when the extension is missing or unsupported.

Changes

Transcription file handling

Layer / File(s) Summary
Whitelisted temporary-file suffix selection
backend/routes/transcription.py
Adds ALLOWED_AUDIO_EXTS and selects the temporary file suffix from the uploaded filename when the extension is approved; otherwise it uses .wav.

Estimated code review effort: 1 (Trivial) | ~3 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preserving the uploaded audio file extension during transcription.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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