sipeed/picoclaw · error
failed to write model_id field: %w
Error message
failed to write model_id field: %w
What it means
Thrown when writer.WriteField("model_id", t.modelID) fails in ElevenLabsTranscriber.Transcribe. WriteField writes a small form field to an in-memory bytes.Buffer; with a healthy runtime it cannot fail. Seeing this error means memory allocation failed inside bytes.Buffer (OOM killer territory) — the surrounding multipart data (a whole audio file) has already been buffered.
Source
Thrown at pkg/audio/asr/elevenlabs_transcriber.go:83
"file_name": filepath.Base(audioFilePath),
})
var requestBody bytes.Buffer
writer := multipart.NewWriter(&requestBody)
part, err := writer.CreateFormFile("file", filepath.Base(audioFilePath))
if err != nil {
logger.ErrorCF("voice", "Failed to create form file", map[string]any{"error": err})
return nil, fmt.Errorf("failed to create form file: %w", err)
}
if _, err = io.Copy(part, audioFile); err != nil {
logger.ErrorCF("voice", "Failed to copy file content", map[string]any{"error": err})
return nil, fmt.Errorf("failed to copy file content: %w", err)
}
if err = writer.WriteField("model_id", t.modelID); err != nil {
return nil, fmt.Errorf("failed to write model_id field: %w", err)
}
if err = writer.Close(); err != nil {
logger.ErrorCF("voice", "Failed to close multipart writer", map[string]any{"error": err})
return nil, fmt.Errorf("failed to close multipart writer: %w", err)
}
url := t.apiBase + "/v1/speech-to-text"
req, err := http.NewRequestWithContext(ctx, "POST", url, &requestBody)
if err != nil {
logger.ErrorCF("voice", "Failed to create request", map[string]any{"error": err})
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Xi-Api-Key", t.apiKey)
logger.DebugCF("voice", "Sending transcription request to ElevenLabs API", map[string]any{View on GitHub (pinned to 49183d7e8d)
Solutions
- Raise the container/process memory limit or cap the accepted audio size.
- Reduce recording length or transcribe in chunks.
- Switch to a streaming-capable path (write the multipart body to a file or use io.Pipe) instead of buffering.
Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(path); err == nil && fi.Size() > maxBufferedAudio {
return fmt.Errorf("audio too large for in-memory multipart build: %d bytes", fi.Size())
} Try / catch
if _, err := el.Transcribe(ctx, path); err != nil {
if runtime/debug memory pressure suspected (OOM kill dmesg entries) {
// reduce audio size / raise memory limit; do not retry unchanged
}
return err
} Prevention
- Cap audio duration/size at intake (e.g. 25MB).
- Run with a memory limit comfortably above 2x the largest recording.
- Alert on container OOM events next to transcription spikes.
When it happens
Trigger: bytes.Buffer.Grow returns an allocation error: process near its memory limit (cgroup OOM pressure) while buffering a large audio file; 32-bit build with >2GB address space exhaustion.
Common situations: Container memory limit set lower than the audio file size plus overhead; very long recordings (hundreds of MB) buffered in RAM before upload.
Related errors
- failed to close multipart writer: %w
- failed to create form file: %w
- failed to copy file content: %w
- failed to open audio file: %w
- failed to get file info: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/3ac726075d384444.
Report an issue: GitHub.