{"record":{"id":"73d5209fe2e5baee","repo":"chenhg5/cc-connect","slug":"pico2wave-read-output-file-w","errorCode":null,"errorMessage":"pico2wave: read output file: %w","messagePattern":"pico2wave: read output file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":646,"sourceCode":"\t// --lang: language code (zh-CN for Chinese, en-US for English)\n\t// --wave: output WAV file path\n\targs := []string{\n\t\t\"--lang=\" + voice,\n\t\t\"--wave=\" + tmpPath,\n\t\ttext,\n\t}\n\n\t// Execute pico2wave command\n\tcmd := exec.CommandContext(ctx, p.Path, args...)\n\toutput, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"pico2wave: voice=%s text=%q: %w, output: %s\", voice, text, err, string(output))\n\t}\n\n\t// Read the generated WAV file\n\taudioData, err := os.ReadFile(tmpPath)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"pico2wave: read output file: %w\", err)\n\t}\n\n\tif len(audioData) == 0 {\n\t\treturn nil, \"\", fmt.Errorf(\"pico2wave: produced empty audio file\")\n\t}\n\n\treturn audioData, \"wav\", nil\n}\n\n// ──────────────────────────────────────────────────────────────\n// EdgeTTS — Microsoft Edge TTS (free, high quality, requires network)\n// ──────────────────────────────────────────────────────────────\n\n// EdgeTTS implements TextToSpeech using Microsoft Edge's free TTS API.\n// This uses the edge-tts CLI command under the hood.\ntype EdgeTTS struct {\n\tPath  string // path to edge-tts executable (empty = \"edge-tts\")\n\tVoice string // default voice (e.g. \"zh-CN-XiaoxiaoNeural\")","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L628-L664","documentation":"After pico2wave exits successfully, PicoTTS.Synthesize reads back the WAV file it was told to write (os.ReadFile on the temp path); this error wraps a failure to read that file. Since CreateTemp succeeded moments earlier, this usually means pico2wave never actually wrote the file (exit 0 without producing output), the file was removed in between, or namespace isolation (e.g. systemd PrivateTmp) gave the child process a different view of the temp directory.","triggerScenarios":"Calling Synthesize via PicoTTS when the pico2wave process returns exit code 0 but does not create/write --wave=<tmpPath> (e.g. empty or no-op text); the temp file is deleted between creation and read; the deferred os.Remove of an overlapping call removes it; or the child runs in a private tmp namespace.","commonSituations":"pico2wave builds that report success while failing to synthesize (empty text producing no output); systemd PrivateTmp or container namespace isolation separating the child's /tmp from the parent's; aggressive /tmp cleaners; text treated as a no-op by the engine.","solutions":["Check file existence right before reading (os.Stat) and report the temp path plus pico2wave's combined output in the error for diagnosis.","Guard empty text before invoking pico2wave: return an error when strings.TrimSpace(text) == \"\".","Re-run the exact command manually to confirm pico2wave creates the file: pico2wave --lang=en-US --wave=/tmp/t.wav \"hello\".","Check for PrivateTmp/namespace isolation (systemd, containers) making the child's tmp differ; use a shared writable directory.","Include tmpPath in the error message to distinguish 'file missing' from 'permission/read failure'."],"exampleFix":"// before\naudioData, err := os.ReadFile(tmpPath)\nif err != nil {\n\treturn nil, \"\", fmt.Errorf(\"pico2wave: read output file: %w\", err)\n}\n// after\nif _, statErr := os.Stat(tmpPath); statErr != nil {\n\treturn nil, \"\", fmt.Errorf(\"pico2wave: wrote no output file %s (exit 0, output: %s): %w\", tmpPath, string(output), statErr)\n}\naudioData, err := os.ReadFile(tmpPath)\nif err != nil {\n\treturn nil, \"\", fmt.Errorf(\"pico2wave: read output file %s: %w\", tmpPath, err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: guard empty text — the main cause of silent no-output runs\nif strings.TrimSpace(text) == \"\" {\n\treturn errors.New(\"pico2wave: empty text\")\n}","typeGuard":null,"tryCatchPattern":"audio, format, err := pico.Synthesize(ctx, text, opts)\nif err != nil {\n\tif strings.Contains(err.Error(), \"read output file\") {\n\t\t// pico2wave exited 0 but wrote nothing — treat as engine failure;\n\t\t// check PrivateTmp/tmp isolation, then retry with another engine\n\t\treturn espeak.Synthesize(ctx, text, opts)\n\t}\n\treturn err\n}","preventionTips":["Reject empty/whitespace-only text before invoking the engine.","Test pico2wave WAV output manually in the target deployment to rule out PrivateTmp/namespace isolation.","Avoid aggressive /tmp cleaners on hosts running local TTS.","Check that the produced WAV is non-empty; a read error usually means no file was written at all."],"tags":["tts","pico2wave","filesystem","file-read"],"backgroundTag":"file-read-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}