jamiepine/voicebox · warning · HTTPException

{exception message from wrapped ValueError}

Error message

{exception message from wrapped ValueError}

What it means

Returned as a 400 from POST /captures wrapping any ValueError raised by captures_service.create_capture. The service uses ValueError to signal expected, user-correctable problems (unsupported audio format, invalid language code, STT model not available, malformed input) rather than internal failures. The route catches ValueError separately from generic Exception so these surface as 400, not 500. The detail is str(e) — the service's own message.

Source

Thrown at backend/routes/captures.py:58

    saved = settings_service.get_capture_settings(db)
    resolved_stt = stt_model or saved.stt_model
    if language is None:
        resolved_language = None if saved.language == "auto" else saved.language
    else:
        resolved_language = None if language == "auto" else language

    try:
        capture = await captures_service.create_capture(
            audio_bytes=audio_bytes,
            filename=file.filename or "capture.wav",
            source=source,
            language=resolved_language,
            stt_model=resolved_stt,
            db=db,
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.exception("Failed to create capture")
        raise HTTPException(status_code=500, detail=str(e))

    return models.CaptureCreateResponse(
        **capture.model_dump(),
        auto_refine=bool(saved.auto_refine),
        allow_auto_paste=bool(saved.allow_auto_paste),
    )


@router.get("/captures", response_model=models.CaptureListResponse)
async def list_captures_endpoint(
    limit: int = 50,
    offset: int = 0,
    db: Session = Depends(get_db),
):
    if limit < 1 or limit > 200:

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Read the detail string — it states the exact problem (model missing, format unsupported, bad language).
  2. If model-related, ensure the STT model is downloaded and matches the configured model_size.
  3. If format-related, convert the upload to a supported container/sample rate before posting.
  4. Validate the language field against the allowed set on the client before sending.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate the inputs the service checks.
const allowedLangs = await fetchAllowedLanguages();
if (language && !allowedLangs.includes(language)) {
  throw new Error(`Unsupported language: ${language}`);
}
if (!await isSttModelInstalled(sttModel)) {
  throw new Error(`STT model ${sttModel} not available`);
}

Type guard

function isSupportedLanguage(lang: string, allowed: string[]): boolean {
  return allowed.includes(lang);
}

Try / catch

try {
  const r = await postCapture(fd);
  if (r.status === 400) {
    const { detail } = await r.json();
    showUserFacingError(detail); // service message names the real cause
    return;
  }
} catch (e) { showNetworkError(e); }

Prevention

When it happens

Trigger: POST /captures where create_capture raises ValueError: e.g. audio_bytes is a format the STT can't decode, resolved_stt_model is not a known/installed model, resolved language code is invalid, or a sample/source reference is malformed.

Common situations: User selected an STT model not yet downloaded; uploaded an audio format the decoder rejects (e.g. mp4 when only wav/16k mono supported); passed an unsupported language string.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/835d9a7e41285c19. Report an issue: GitHub.