chenhg5/cc-connect · error

espeak: voice= text=

Error message

espeak: voice=%s text=%q: %w

What it means

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.

Solutions

  1. Verify espeak is installed and runnable: `which espeak` / `espeak --version`; set EspeakTTS.Path to the full binary path if it's not on PATH.
  2. Reproduce manually with the exact arguments: espeak -v <voice> -w /dev/stdout "<text>" > /tmp/out.wav and read stderr for the real failure.
  3. Install the missing voice data for the configured voice (language packs / espeak-ng-data) or switch Voice to an installed one.
  4. If the host uses espeak-ng, check flag compatibility or point Path at espeak-ng with equivalent arguments.
  5. On non-Unix platforms, write WAV to a temp file instead of /dev/stdout.

Example fix

// before
voice := "zh+f3" // voice data not installed on host
output, _, err := e.Synthesize(ctx, text, core.TTSSynthesisOpts{})
// after
voice := "zh" // verified present: espeak --voices | grep zh
output, _, err := e.Synthesize(ctx, text, core.TTSSynthesisOpts{})
if err != nil {
	var ee *exec.ExitError
	if errors.As(err, &ee) {
		log.Printf("espeak stderr: %s", ee.Stderr)
	}
}
Defensive patterns

Strategy: fallback

Validate before calling

// Go: check the binary and voice before using EspeakTTS
p, err := exec.LookPath("espeak")
if err != nil { /* espeak missing: install it or pick another engine */ }
out, _ := exec.Command(p, "--voices").Output()
if !strings.Contains(string(out), voice) { /* voice not installed */ }

Type guard

func espeakAvailable(path string) bool {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	return exec.CommandContext(ctx, path, "--version").Run() == nil
}

Try / catch

audio, format, err := espeak.Synthesize(ctx, text, opts)
if err != nil {
	var execErr *exec.Error
	if errors.As(err, &execErr) {
		log.Printf("espeak binary not found: %v — install espeak or set Path", execErr)
	}
	// fallback: try PicoTTS or cloud TTS
	return picoTTS.Synthesize(ctx, text, opts)
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/1c22b6f3775507c6. Report an issue: GitHub.

Appendix: source

Thrown at core/tts.go:580

	}

	// Add speed option if specified
	if opts.Speed > 0 {
		// espeak speed is in words per minute, default 160
		// Convert speed multiplier (0.5-2.0) to wpm
		wpm := int(160 * opts.Speed)
		args = append(args, "-s", fmt.Sprintf("%d", wpm))
	}

	// Add text as argument
	args = append(args, text)

	// Execute espeak command
	// Use Output() instead of CombinedOutput() to avoid mixing stderr warnings with audio data
	cmd := exec.CommandContext(ctx, e.Path, args...)
	output, err := cmd.Output()
	if err != nil {
		return nil, "", fmt.Errorf("espeak: voice=%s text=%q: %w", voice, text, err)
	}

	return output, "wav", nil
}

// ──────────────────────────────────────────────────────────────
// PicoTTS — Google Pico TTS (better quality than espeak, offline)
// ──────────────────────────────────────────────────────────────

// PicoTTS implements TextToSpeech using pico2wave (Google Pico TTS).
type PicoTTS struct {
	Path  string // path to pico2wave executable (empty = "pico2wave")
	Voice string // default voice language (e.g. "zh-CN", "en-US")
}

// NewPicoTTS creates a new PicoTTS instance.
func NewPicoTTS(path, voice string) *PicoTTS {
	if path == "" {

View on GitHub (pinned to 4000b2338a)