jamiepine/voicebox · error · Error
HTTP ${res.status}
Error message
HTTP ${res.status} What it means
Thrown by `importAudio(file)` (client.ts:279-291) when `POST /generate/import` (multipart audio) returns non-2xx. NOTE: this method diverges from the rest of the client — it reads the body as `text()` (not JSON) and its fallback message is `HTTP ${res.status}` (no `error!` wording, no `formatErrorDetail`). So the surfaced message is either the raw server text or a terse `HTTP <code>`.
Source
Thrown at app/src/lib/api/client.ts:288
});
}
async regenerateGeneration(generationId: string): Promise<GenerationResponse> {
return this.request<GenerationResponse>(`/generate/${generationId}/regenerate`, {
method: 'POST',
});
}
async importAudio(file: File): Promise<GenerationResponse> {
const form = new FormData();
form.append('file', file);
const res = await fetch(`${this.getBaseUrl()}/generate/import`, {
method: 'POST',
body: form,
});
if (!res.ok) {
const detail = await res.text().catch(() => res.statusText);
throw new Error(detail || `HTTP ${res.status}`);
}
return res.json();
}
async toggleFavorite(generationId: string): Promise<{ is_favorited: boolean }> {
return this.request<{ is_favorited: boolean }>(`/history/${generationId}/favorite`, {
method: 'POST',
});
}
// History
async listHistory(query?: HistoryQuery): Promise<HistoryListResponse> {
const params = new URLSearchParams();
if (query?.profile_id) params.append('profile_id', query.profile_id);
if (query?.search) params.append('search', query.search);
if (query?.limit) params.append('limit', query.limit.toString());
if (query?.offset) params.append('offset', query.offset.toString());
View on GitHub (pinned to 51f49dea19)
Solutions
- Read the raw text body the message carries — unlike other errors it is the literal server response, which usually names the unsupported codec.
- Convert the file to wav/mp3 client-side or ask the user to re-export before importing.
- Confirm ffmpeg is installed and on PATH in the backend environment.
- On 413, shrink the file; on 500 check backend logs for the decoder error.
Example fix
// before
const g = await api.importAudio(file);
// after — prefer widely-supported containers
const OK = ['audio/wav', 'audio/x-wav', 'audio/mpeg', 'audio/mp3'];
if (!OK.includes(file.type)) throw new Error('Import WAV or MP3 only');
const g = await api.importAudio(file); Defensive patterns
Strategy: validation
Validate before calling
const OK_AUDIO = ['audio/wav', 'audio/x-wav', 'audio/mpeg', 'audio/mp3'];
function validateImportAudio(f: File) {
if (!OK_AUDIO.includes(f.type)) throw new Error('Import WAV or MP3 only');
} Type guard
function isImportableAudio(f: File): boolean {
return ['audio/wav', 'audio/x-wav', 'audio/mpeg', 'audio/mp3'].includes(f.type);
} Try / catch
try {
validateImportAudio(file);
return await api.importAudio(file);
} catch (e) {
// importAudio surfaces raw text — show it directly
toast.error(`Import failed: ${(e as Error).message}`);
} Prevention
- Note this endpoint returns raw text errors (not JSON) — surface the message verbatim.
- Confirm ffmpeg is on the backend PATH for exotic codecs.
- Pre-convert unusual containers to wav/mp3.
When it happens
Trigger: Audio codec/container not supported by the backend's ffmpeg/decoder pipeline; file too large; corrupt/truncated audio; backend cannot probe duration; backend model unavailable to attach the imported audio to a generation.
Common situations: User drags in an `.m4a`, `.ogg`, or unusual container the backend ffmpeg build lacks a codec for; partial upload; backend ffmpeg binary missing from the PATH so probing throws a 500.
Related errors
- Unsupported audio format '{suffix}'. Allowed: {sorted(IMPORT
- File exceeds {IMPORT_AUDIO_MAX_BYTES // (1024 * 1024)} MB li
- Empty audio file.
- Could not decode audio: {decode_err}
- HTTP error! status: ${response.status}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/96de6cae7d116a73.
Report an issue: GitHub.