{"record":{"id":"61c4b453e0594880","repo":"odysseus-dev/odysseus","slug":"transcription-failed-str-e","errorCode":null,"errorMessage":"Transcription failed: {str(e)}","messagePattern":"Transcription failed: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"routes/stt_routes.py","lineNumber":52,"sourceCode":"\n            audio_bytes = await read_upload_limited(file, STT_MAX_AUDIO_BYTES, \"Audio file\")\n            if not audio_bytes:\n                raise HTTPException(status_code=400, detail={\"message\": \"Empty audio file\"})\n\n            text = stt_service.transcribe(audio_bytes)\n            if text is None:\n                raise HTTPException(\n                    status_code=500,\n                    detail={\"message\": \"Transcription failed\"}\n                )\n\n            return {\"text\": text}\n\n        except HTTPException:\n            raise\n        except Exception as e:\n            logger.error(f\"Transcription error: {e}\", exc_info=True)\n            raise HTTPException(\n                status_code=500,\n                detail={\"message\": f\"Transcription failed: {str(e)}\"}\n            )\n\n    return router\n","sourceCodeStart":34,"sourceCodeEnd":58,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/stt_routes.py#L34-L58","documentation":"Raised by the same STT endpoint when an unexpected (non-HTTPException) exception escapes the request body — the generic except Exception handler at stt_routes.py wraps it into HTTP 500 with detail \"Transcription failed: {str(e)}\". The embedded str(e) is the original exception message, so the body carries the root cause while the server log carries the full traceback via logger.error(..., exc_info=True).","triggerScenarios":"Any unhandled exception inside the route after the HTTPException guards: read_upload_limited raising a non-HTTP error (I/O hiccup, malformed multipart), stt_service.transcribe raising (model crash, CUDA error), or a bug in response serialization. The client sees 500 with the exception text appended.","commonSituations":"Multipart body truncated mid-upload; ffmpeg/av library missing so decode raises instead of returning None; CUDA device assert; temporary file permission errors in the upload spool directory; version mismatch between the audio decode lib and the model wrapper.","solutions":["Read the message text after 'Transcription failed:' — it names the underlying exception (e.g. 'ffmpeg returned non-zero exit status', 'CUDA out of memory').","Match that message to the fix: install ffmpeg / free GPU memory / fix temp-dir permissions.","Correlate with the server log entry 'Transcription error: {e}' (full traceback) for the stack trace.","If the exception text leaks sensitive paths, wrap detail as a generic message server-side and keep specifics in logs only."],"exampleFix":"# before\nexcept Exception as e:\n    raise HTTPException(500, f\"Transcription failed: {str(e)}\")\n\n# after: keep detail in logs, return stable message\nexcept Exception as e:\n    logger.error(f\"Transcription error: {e}\", exc_info=True)\n    raise HTTPException(500, {\"message\": \"Transcription failed\", \"error_id\": log_context_id})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isSttErrorDetail(v: unknown): v is { message: string } {\n  return typeof v === 'object' && v !== null && typeof (v as any).message === 'string';\n}","tryCatchPattern":"try {\n  const res = await fetch('/api/stt/transcribe', {method:'POST', body: fd});\n  if (!res.ok) {\n    const d = await res.json().catch(() => null);\n    const msg = d?.detail?.message ?? `HTTP ${res.status}`;\n    logToTelemetry('stt_failed', {msg});\n    throw new TranscriptionError(msg);\n  }\n} catch (e) { /* single place: retry once, then fall back to browser STT */ }","preventionTips":["Wrap the upload in a timeout so truncated multipart bodies never reach the handler.","Smoke-test STT on deploy: send a 1-second silent WAV and assert 200.","Do not surface raw str(e) to end users; log it server-side with exc_info (already done) and show a generic message client-side.","Pin ffmpeg/av library versions in the deployment image."],"tags":["stt","audio","fastapi","http-500","unhandled-exception"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}