sipeed/picoclaw · error
failed to open audio file: %w
Error message
failed to open audio file: %w
What it means
Thrown by ElevenLabsTranscriber.Transcribe when os.Open(audioFilePath) fails, before any multipart body is built. The error wraps a *os.PathError whose Op is 'open'. No network call is attempted; the ElevenLabs API key is irrelevant to this failure.
Source
Thrown at pkg/audio/asr/elevenlabs_transcriber.go:53
}
return &ElevenLabsTranscriber{
apiKey: apiKey,
apiBase: apiBase,
modelID: modelID,
httpClient: &http.Client{
Timeout: 120 * time.Second,
},
}
}
func (t *ElevenLabsTranscriber) Transcribe(ctx context.Context, audioFilePath string) (*TranscriptionResponse, error) {
logger.InfoCF("voice", "Starting ElevenLabs transcription", map[string]any{"audio_file": audioFilePath})
audioFile, err := os.Open(audioFilePath)
if err != nil {
logger.ErrorCF("voice", "Failed to open audio file", map[string]any{"path": audioFilePath, "error": err})
return nil, fmt.Errorf("failed to open audio file: %w", err)
}
defer audioFile.Close()
fileInfo, err := audioFile.Stat()
if err != nil {
logger.ErrorCF("voice", "Failed to get file info", map[string]any{"path": audioFilePath, "error": err})
return nil, fmt.Errorf("failed to get file info: %w", err)
}
logger.DebugCF("voice", "Audio file details", map[string]any{
"size_bytes": fileInfo.Size(),
"file_name": filepath.Base(audioFilePath),
})
var requestBody bytes.Buffer
writer := multipart.NewWriter(&requestBody)
part, err := writer.CreateFormFile("file", filepath.Base(audioFilePath))View on GitHub (pinned to 49183d7e8d)
Solutions
- Verify the path with ls/stat in the same environment the transcriber runs in.
- Fix permissions (chmod/chown) if EACCES; check fd usage (lsof | wc -l) if EMFILE.
- Ensure the caller keeps the recorded file alive until Transcribe returns.
- Pre-validate with os.Stat before invoking Transcribe.
Example fix
// before
resp, err := elevenLabs.Transcribe(ctx, tmpPath)
// after
if _, err := os.Stat(tmpPath); err != nil {
return fmt.Errorf("cannot transcribe, audio file unreadable: %w", err)
}
resp, err := elevenLabs.Transcribe(ctx, tmpPath) Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(audioFilePath); err != nil {
return fmt.Errorf("audio missing: %w", err)
} else if fi.IsDir() || fi.Size() == 0 {
return fmt.Errorf("audio invalid (dir or empty): %s", audioFilePath)
} Type guard
func isNotFound(err error) bool { return errors.Is(err, fs.ErrNotExist) } Try / catch
if _, err := el.Transcribe(ctx, path); err != nil {
if isNotFound(err) {
log.Printf("recording vanished: %s", path) // pipeline bug, no retry
return
}
return err
} Prevention
- Delete temp audio only after Transcribe returns, not on cancellation races.
- Run the service as the user that owns the recordings directory.
- Watch fd counts in long-running agents.
When it happens
Trigger: os.Open fails with ENOENT (file missing), EACCES (no read permission), EISDIR (path is a directory), or EMFILE (process out of file descriptors after leaking handles).
Common situations: Temp audio file already cleaned by a cleanup routine; file recorded in a container but transcription runs on the host (or vice versa); fd leak in a long-running agent after many recordings without Close.
Related errors
- failed to read audio file: %w
- failed to get file info: %w
- failed to copy file content: %w
- failed to open audio file %s: %w
- transcription request failed: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/e6aba657a80cc015.
Report an issue: GitHub.