{"record":{"id":"e6aba657a80cc015","repo":"sipeed/picoclaw","slug":"failed-to-open-audio-file-w","errorCode":null,"errorMessage":"failed to open audio file: %w","messagePattern":"failed to open audio file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/asr/elevenlabs_transcriber.go","lineNumber":53,"sourceCode":"\t}\n\n\treturn &ElevenLabsTranscriber{\n\t\tapiKey:  apiKey,\n\t\tapiBase: apiBase,\n\t\tmodelID: modelID,\n\t\thttpClient: &http.Client{\n\t\t\tTimeout: 120 * time.Second,\n\t\t},\n\t}\n}\n\nfunc (t *ElevenLabsTranscriber) Transcribe(ctx context.Context, audioFilePath string) (*TranscriptionResponse, error) {\n\tlogger.InfoCF(\"voice\", \"Starting ElevenLabs transcription\", map[string]any{\"audio_file\": audioFilePath})\n\n\taudioFile, err := os.Open(audioFilePath)\n\tif err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to open audio file\", map[string]any{\"path\": audioFilePath, \"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to open audio file: %w\", err)\n\t}\n\tdefer audioFile.Close()\n\n\tfileInfo, err := audioFile.Stat()\n\tif err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to get file info\", map[string]any{\"path\": audioFilePath, \"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to get file info: %w\", err)\n\t}\n\n\tlogger.DebugCF(\"voice\", \"Audio file details\", map[string]any{\n\t\t\"size_bytes\": fileInfo.Size(),\n\t\t\"file_name\":  filepath.Base(audioFilePath),\n\t})\n\n\tvar requestBody bytes.Buffer\n\twriter := multipart.NewWriter(&requestBody)\n\n\tpart, err := writer.CreateFormFile(\"file\", filepath.Base(audioFilePath))","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/asr/elevenlabs_transcriber.go#L35-L71","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nresp, err := elevenLabs.Transcribe(ctx, tmpPath)\n\n// after\nif _, err := os.Stat(tmpPath); err != nil {\n    return fmt.Errorf(\"cannot transcribe, audio file unreadable: %w\", err)\n}\nresp, err := elevenLabs.Transcribe(ctx, tmpPath)","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(audioFilePath); err != nil {\n    return fmt.Errorf(\"audio missing: %w\", err)\n} else if fi.IsDir() || fi.Size() == 0 {\n    return fmt.Errorf(\"audio invalid (dir or empty): %s\", audioFilePath)\n}","typeGuard":"func isNotFound(err error) bool { return errors.Is(err, fs.ErrNotExist) }","tryCatchPattern":"if _, err := el.Transcribe(ctx, path); err != nil {\n    if isNotFound(err) {\n        log.Printf(\"recording vanished: %s\", path) // pipeline bug, no retry\n        return\n    }\n    return err\n}","preventionTips":["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."],"tags":["filesystem","elevenlabs","audio","transcription","go"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}