{"record":{"id":"1c22b6f3775507c6","repo":"chenhg5/cc-connect","slug":"espeak-voice-s-text-q-w","errorCode":null,"errorMessage":"espeak: voice=%s text=%q: %w","messagePattern":"espeak: voice=(.+?) text=%q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":580,"sourceCode":"\t}\n\n\t// Add speed option if specified\n\tif opts.Speed > 0 {\n\t\t// espeak speed is in words per minute, default 160\n\t\t// Convert speed multiplier (0.5-2.0) to wpm\n\t\twpm := int(160 * opts.Speed)\n\t\targs = append(args, \"-s\", fmt.Sprintf(\"%d\", wpm))\n\t}\n\n\t// Add text as argument\n\targs = append(args, text)\n\n\t// Execute espeak command\n\t// Use Output() instead of CombinedOutput() to avoid mixing stderr warnings with audio data\n\tcmd := exec.CommandContext(ctx, e.Path, args...)\n\toutput, err := cmd.Output()\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"espeak: voice=%s text=%q: %w\", voice, text, err)\n\t}\n\n\treturn output, \"wav\", nil\n}\n\n// ──────────────────────────────────────────────────────────────\n// PicoTTS — Google Pico TTS (better quality than espeak, offline)\n// ──────────────────────────────────────────────────────────────\n\n// PicoTTS implements TextToSpeech using pico2wave (Google Pico TTS).\ntype PicoTTS struct {\n\tPath  string // path to pico2wave executable (empty = \"pico2wave\")\n\tVoice string // default voice language (e.g. \"zh-CN\", \"en-US\")\n}\n\n// NewPicoTTS creates a new PicoTTS instance.\nfunc NewPicoTTS(path, voice string) *PicoTTS {\n\tif path == \"\" {","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L562-L598","documentation":"EspeakTTS.Synthesize runs the local espeak binary with `-v <voice> -w /dev/stdout [speed] <text>` and captures stdout; if the command exits non-zero the library wraps the exec error with the voice and text for context. The wrapped err is typically *exec.ExitError (espeak failed) or *exec.Error (binary not found). Because Output() is used rather than CombinedOutput(), espeak's own stderr diagnostics are not included, so the real cause is hidden.","triggerScenarios":"Calling Synthesize via EspeakTTS when: the espeak executable is missing or Path is misconfigured; the voice string is invalid or its language data is not installed; the text argument breaks espeak; the context is cancelled mid-run; or WAV-to-/dev/stdout fails (platforms lacking /dev/stdout semantics, e.g. Windows).","commonSituations":"Deploying to a container/minimal host without espeak installed; configuring Voice to a language whose espeak voice data (mbrola/dictionary) is absent; OS upgrades replacing espeak with espeak-ng and different flag behavior; running on Windows where `-w /dev/stdout` is unsupported.","solutions":["Verify espeak is installed and runnable: `which espeak` / `espeak --version`; set EspeakTTS.Path to the full binary path if it's not on PATH.","Reproduce manually with the exact arguments: espeak -v <voice> -w /dev/stdout \"<text>\" > /tmp/out.wav and read stderr for the real failure.","Install the missing voice data for the configured voice (language packs / espeak-ng-data) or switch Voice to an installed one.","If the host uses espeak-ng, check flag compatibility or point Path at espeak-ng with equivalent arguments.","On non-Unix platforms, write WAV to a temp file instead of /dev/stdout."],"exampleFix":"// before\nvoice := \"zh+f3\" // voice data not installed on host\noutput, _, err := e.Synthesize(ctx, text, core.TTSSynthesisOpts{})\n// after\nvoice := \"zh\" // verified present: espeak --voices | grep zh\noutput, _, err := e.Synthesize(ctx, text, core.TTSSynthesisOpts{})\nif err != nil {\n\tvar ee *exec.ExitError\n\tif errors.As(err, &ee) {\n\t\tlog.Printf(\"espeak stderr: %s\", ee.Stderr)\n\t}\n}","handlingStrategy":"fallback","validationCode":"// Go: check the binary and voice before using EspeakTTS\np, err := exec.LookPath(\"espeak\")\nif err != nil { /* espeak missing: install it or pick another engine */ }\nout, _ := exec.Command(p, \"--voices\").Output()\nif !strings.Contains(string(out), voice) { /* voice not installed */ }","typeGuard":"func espeakAvailable(path string) bool {\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\tdefer cancel()\n\treturn exec.CommandContext(ctx, path, \"--version\").Run() == nil\n}","tryCatchPattern":"audio, format, err := espeak.Synthesize(ctx, text, opts)\nif err != nil {\n\tvar execErr *exec.Error\n\tif errors.As(err, &execErr) {\n\t\tlog.Printf(\"espeak binary not found: %v — install espeak or set Path\", execErr)\n\t}\n\t// fallback: try PicoTTS or cloud TTS\n\treturn picoTTS.Synthesize(ctx, text, opts)\n}","preventionTips":["Run exec.LookPath(espeakPath) at startup (doctor check) and fail fast with install instructions.","Verify the configured voice exists via `espeak --voices` at config load time.","On Windows/containers, write WAV to a temp file instead of /dev/stdout.","Pin espeak vs espeak-ng compatibility in deployment images."],"tags":["tts","espeak","exec","external-command"],"backgroundTag":"git-command-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}