sipeed/picoclaw · error
failed to copy file content: %w
Error message
failed to copy file content: %w
What it means
Thrown when io.Copy(part, bytes.NewReader(data)) fails while copying the already-in-memory audio bytes into the multipart buffer in WhisperTranscriber. Both ends are memory buffers; a copy error here requires bytes.Buffer write/allocation failure (out of memory). Under a healthy runtime this is unreachable.
Source
Thrown at pkg/audio/asr/whisper_transcriber.go:112
logger.InfoCF("voice", "Starting whisper transcription from memory", map[string]any{
"bytes": len(data),
"filename": filename,
"model": t.modelID,
"provider": t.providerName,
})
var requestBody bytes.Buffer
writer := multipart.NewWriter(&requestBody)
part, err := writer.CreateFormFile("file", filename)
if err != nil {
logger.ErrorCF("voice", "Failed to create whisper form file", map[string]any{"error": err})
return nil, fmt.Errorf("failed to create form file: %w", err)
}
if _, copyErr := io.Copy(part, bytes.NewReader(data)); copyErr != nil {
logger.ErrorCF("voice", "Failed to copy whisper file content", map[string]any{"error": copyErr})
return nil, fmt.Errorf("failed to copy file content: %w", copyErr)
}
if err = writer.WriteField("model", t.modelID); err != nil {
logger.ErrorCF("voice", "Failed to write whisper model field", map[string]any{"error": err})
return nil, fmt.Errorf("failed to write model field: %w", err)
}
if err = writer.WriteField("response_format", "json"); err != nil {
logger.ErrorCF("voice", "Failed to write whisper response_format field", map[string]any{"error": err})
return nil, fmt.Errorf("failed to write response_format field: %w", err)
}
if err = writer.Close(); err != nil {
logger.ErrorCF("voice", "Failed to close whisper multipart writer", map[string]any{"error": err})
return nil, fmt.Errorf("failed to close multipart writer: %w", err)
}
return t.doRequest(ctx, &requestBody, writer.FormDataContentType(), int64(len(data)))View on GitHub (pinned to 49183d7e8d)
Solutions
- Cap accepted audio size before transcription.
- Raise memory limits or process audio in segments.
- Pre-size the buffer (requestBody.Grow(len(data)+overhead)) to avoid repeated reallocation.
Example fix
// before var requestBody bytes.Buffer writer := multipart.NewWriter(&requestBody) // after: pre-allocate to avoid mid-copy growth failure var requestBody bytes.Buffer requestBody.Grow(len(data) + len(data)/10 + 1024) writer := multipart.NewWriter(&requestBody)
Defensive patterns
Strategy: try-catch
Validate before calling
const maxInMemoryAudio = 100 << 20 // 100MB
if len(data) > maxInMemoryAudio {
return fmt.Errorf("audio blob %d bytes exceeds in-memory limit %d", len(data), maxInMemoryAudio)
} Try / catch
if _, err := whisper.TranscribeWithData(ctx, data, name); err != nil {
if len(data) > maxInMemoryAudio {
return errors.New("audio too large for in-memory transcription; use the file-based Transcribe")
}
return err
} Prevention
- Enforce a size cap before calling the bytes-based API.
- Prefer the file-based Transcribe for large audio; it avoids duplicating the blob.
When it happens
Trigger: Allocation failure while doubling the buffer for a large audio blob; container OOM pressure with a multi-hundred-MB recording duplicated in memory (data + requestBody).
Common situations: Transcribing very long in-memory recordings inside memory-capped pods; the copy doubles peak RSS because the audio exists twice (data and multipart copy).
Related errors
- failed to write model_id field: %w
- failed to close multipart writer: %w
- failed to create form file: %w
- failed to write model field: %w
- failed to write response_format field: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/339e55d1499c087d.
Report an issue: GitHub.