sipeed/picoclaw · error
transcription request failed: %w
Error message
transcription request failed: %w
What it means
Thrown when the underlying provider.Chat call fails while sending the base64-encoded audio (data:audio/<fmt>;base64,... media attachment) to the configured chat model. This wraps whatever error the providers layer produced: HTTP transport failure, non-2xx API response, model rejection of audio input, or context cancellation. The error is wrapped with %w so errors.As/Is can reach provider-specific error types.
Source
Thrown at pkg/audio/asr/audio_model_transcriber.go:81
if err != nil {
logger.ErrorCF("voice", "Failed to detect audio format", map[string]any{"path": audioFilePath, "error": err})
return nil, err
}
resp, err := t.provider.Chat(ctx, []providers.Message{
{
Role: "user",
Content: t.prompt,
Media: []string{
fmt.Sprintf("data:audio/%s;base64,%s", format, base64.StdEncoding.EncodeToString(audioBytes)),
},
},
}, nil, t.modelID, map[string]any{
"temperature": 0,
})
if err != nil {
logger.ErrorCF("voice", "Audio model transcription request failed", map[string]any{"error": err})
return nil, fmt.Errorf("transcription request failed: %w", err)
}
text := strings.TrimSpace(resp.Content)
logger.InfoCF("voice", "Audio model transcription completed successfully", map[string]any{
"text_length": len(text),
"transcription_preview": utils.Truncate(text, 50),
})
return &TranscriptionResponse{Text: text}, nil
}
func (t *AudioModelTranscriber) Name() string {
return "audio-model"
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Inspect the wrapped error with errors.As for the provider's HTTP error type to get status code and response body.
- Verify the model configured for this transcriber actually accepts audio input media (check supportsAudioTranscription in pkg/audio/asr/asr.go and the model list).
- Confirm the API key/base URL in the model config is valid for that protocol.
- For transient transport errors (timeout, connection reset), retry with backoff; for 4xx do not retry.
- For long audio, switch to ElevenLabsTranscriber or WhisperTranscriber which upload raw files instead of base64 chat payloads.
Example fix
// before
resp, err := t.provider.Chat(ctx, msgs, nil, t.modelID, opts)
if err != nil { return nil, err }
// after (caller side, with retry on transient failures)
var httpErr *api.HTTPError
if errors.As(err, &httpErr) && httpErr.StatusCode >= 500 && httpErr.StatusCode < 600 {
// transient upstream failure: safe to retry
return retryWithBackoff(ctx, func() (*TranscriptionResponse, error) {
return transcriber.Transcribe(ctx, path)
})
} Defensive patterns
Strategy: retry
Validate before calling
// Before first use: smoke-test the chat provider with a tiny payload.
if _, err := provider.Chat(ctx, []providers.Message{{Role: "user", Content: "ping"}}, nil, modelID, nil); err != nil {
return fmt.Errorf("audio transcriber backend unhealthy: %w", err)
} Type guard
func isRetryableProviderErr(err error) bool {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() { return true }
if errors.Is(err, context.DeadlineExceeded) { return true }
var httpErr *api.HTTPError
return errors.As(err, &httpErr) && httpErr.StatusCode >= 500 && httpErr.StatusCode < 600
} Try / catch
resp, err := transcriber.Transcribe(ctx, path)
if err != nil {
if isRetryableProviderErr(err) {
resp, err = backoff.Retry(ctx, 3, time.Second, func() (*asr.TranscriptionResponse, error) {
return transcriber.Transcribe(ctx, path)
})
}
if err != nil { return fmt.Errorf("audio-model transcription failed: %w", err) }
} Prevention
- Pick an audio-capable model (OpenAI-compatible multimodal) when constructing the transcriber.
- Keep base64 payload small: downsample to 16kHz mono before transcription.
- Set a caller ctx deadline larger than expected transcription time to distinguish cancel from failure.
When it happens
Trigger: provider.Chat(ctx, messages, nil, t.modelID, {temperature: 0}) returns an error: network/DNS/TLS failure to the LLM endpoint; 401/403 from an invalid or missing API key; 404 when modelID does not exist; 4xx when the model does not accept audio media parts (only OpenAI-compatible audio models work); 413 when the base64 payload exceeds the gateway limit; ctx cancelled or deadline exceeded.
Common situations: Model config points at a text-only model (e.g. plain gpt-4o instead of an audio-capable variant); API key env var not exported in the service environment; very long recordings inflate the base64 payload past a reverse-proxy body limit; user cancels the turn mid-request.
Related errors
- LLM call failed after retries: %w
- after %d retries: %w
- error fetching models: %w
- failed to read audio file: %w
- failed to open audio file: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/95e8abb4217258a6.
Report an issue: GitHub.