{"record":{"id":"1f76616bb4810eb1","repo":"sipeed/picoclaw","slug":"failed-to-register-audio-w","errorCode":null,"errorMessage":"failed to register audio: %w","messagePattern":"failed to register audio: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/tts/tts.go","lineNumber":177,"sourceCode":"\tif filename == \"\" {\n\t\tfilename = fmt.Sprintf(\"tts-%d%s\", time.Now().Unix(), fileExt)\n\t}\n\n\text := strings.ToLower(filepath.Ext(filename))\n\tif ext == \"\" {\n\t\tfilename += fileExt\n\t} else if ext != fileExt {\n\t\tfilename = strings.TrimSuffix(filename, filepath.Ext(filename)) + fileExt\n\t}\n\n\tscope := fmt.Sprintf(\"tool:send_tts:%s:%s:%d\", channel, chatID, time.Now().UnixNano())\n\tref, err := store.Store(file.Name(), media.MediaMeta{\n\t\tFilename:    filename,\n\t\tContentType: contentType,\n\t\tSource:      \"tool:send_tts\",\n\t}, scope)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to register audio: %w\", err)\n\t}\n\tremoveTemp = false\n\n\treturn ref, nil\n}\n","sourceCodeStart":159,"sourceCodeEnd":183,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/tts/tts.go#L159-L183","documentation":"store.Store(file.Name(), media.MediaMeta{...}, scope) failed at pkg/audio/tts/tts.go:177 while registering the finished temp audio file into the media store under scope \"tool:send_tts:<channel>:<chatID>:<unixnano>\". The wrapped error comes from the media store implementation — typically a copy/import into the store's backing directory failing or the store being unavailable/misconfigured. Because removeTemp stays true on this path, the temp file is cleaned up and the caller gets no reference.","triggerScenarios":"Store's target directory unwritable or full when importing the temp file; store not initialized / nil from missing media config; store backend rejecting the metadata (e.g. filename/content-type handling); filesystem errors moving the file into the store.","commonSituations":"Media store dir on a different volume than the temp dir, with the store volume full or read-only; running with a media store path the service user cannot write; store dir deleted while service runs.","solutions":["Read the wrapped error — it names the store operation and underlying errno","Verify the media store directory exists, is owned by the service user, and is writable: mkdir -p <store> && sudo -u <svc> test -w <store>","Check disk space on the store's filesystem (it may be a different volume than the temp dir)","Restart the service after fixing media store config so the store re-initializes"],"exampleFix":"# before: store dir owned by root, service runs as 'picoclaw'\nls -ld /var/lib/picoclaw/media  # drwx------ root root\n\n# after:\nchown -R picoclaw:picoclaw /var/lib/picoclaw/media\nchmod 700 /var/lib/picoclaw/media","handlingStrategy":"try-catch","validationCode":"func mediaStoreWritable(storeDir string) error {\n    if err := os.MkdirAll(storeDir, 0o700); err != nil { return err }\n    probe := filepath.Join(storeDir, \".probe\")\n    if err := os.WriteFile(probe, nil, 0o600); err != nil { return err }\n    return os.Remove(probe)\n}","typeGuard":null,"tryCatchPattern":"if _, err := tts.SynthesizeToStore(ctx, text, ch, chatID, name); err != nil {\n    if strings.Contains(err.Error(), \"failed to register audio\") {\n        // temp audio worked, store import failed: check store volume/config\n        log.Print(\"media store import failed; verify store dir perms and space\")\n    }\n    return err\n}","preventionTips":["Startup-check writability of the media store directory as the service user","Monitor disk space on the store volume separately from the temp volume","Keep store and temp dirs on the same writable local filesystem when possible"],"tags":["go","storage","tts","media","permissions"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}