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

  1. Raise the container/process memory limit or cap the accepted audio size.
  2. Reduce recording length or transcribe in chunks.
  3. 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

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


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/3ac726075d384444. Report an issue: GitHub.