chenhg5/cc-connect · error

tts is not configured

Error message

tts is not configured

What it means

Engine.synthesizeAndSendTTS guards TTS synthesis: if the Engine has no TTS config at all (e.tts is nil) or the [tts] section exists but is disabled (Enabled=false), voice synthesis cannot proceed and this error is returned instead of generating audio.

Source

Thrown at core/engine.go:15869

		chunks = append(chunks, string(runes[:end]))
		runes = runes[end:]
	}
	return chunks
}

// sendTTSReply synthesizes fullResponse text and sends audio to the platform.
// Called asynchronously after EventResult; text reply is always sent first.
func (e *Engine) sendTTSReply(p Platform, replyCtx any, text string) {
	slog.Debug("tts: sendTTSReply called", "platform", p.Name(), "text_len", len(text))
	if err := e.synthesizeAndSendTTS(p, replyCtx, text); err != nil {
		slog.Error("tts: voice reply failed", "platform", p.Name(), "error", err)
	}
}

func (e *Engine) synthesizeAndSendTTS(p Platform, replyCtx any, text string) error {
	if e.tts == nil || !e.tts.Enabled {
		return fmt.Errorf("tts is not configured")
	}
	if e.tts.TTS == nil {
		return fmt.Errorf("tts provider is not configured")
	}
	if e.tts.MaxTextLen > 0 && utf8.RuneCountInString(text) > e.tts.MaxTextLen {
		return fmt.Errorf("text exceeds max_text_len (%d > %d)", utf8.RuneCountInString(text), e.tts.MaxTextLen)
	}
	as, ok := p.(AudioSender)
	if !ok {
		return fmt.Errorf("platform %s does not support audio sending", p.Name())
	}
	slog.Info("tts: starting synthesis", "voice", e.tts.Voice, "speed", e.tts.Speed, "text_len", len(text))
	opts := TTSSynthesisOpts{
		Voice:        e.tts.Voice,
		LanguageType: e.tts.LanguageType,
		Speed:        e.tts.Speed,
	}
	audioData, format, err := e.tts.TTS.Synthesize(e.ctx, StripMarkdown(text), opts)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Add a [tts] section with enabled = true and a valid provider configuration in config.toml
  2. Configure the TTS provider (credentials, voice, etc.) and restart the daemon
  3. Use a text reply instead of voice if TTS is intentionally disabled
  4. Guard the command handler with a TTS-enabled check and tell the user how to enable it

Example fix

// before (config.toml)
# no tts section
// after (config.toml)
[tts]
enabled = true
provider = "feishu"
voice = "default"
Defensive patterns

Strategy: fallback

Validate before calling

if cfg.TTS == nil || !cfg.TTS.Enabled {
    reply("voice replies are disabled; add [tts] enabled=true to config.toml")
    return
}

Type guard

func ttsAvailable(e *core.Engine) bool { return e != nil && e.TTSConfig() != nil && e.TTSConfig().Enabled }

Try / catch

if err := e.SynthesizeAndSendTTS(p, replyCtx, text); err != nil {
    if strings.Contains(err.Error(), "tts is not configured") {
        slog.Warn("tts disabled, falling back to text reply")
        p.Reply(replyCtx, text)
        return
    }
    slog.Error("tts failed", "err", err)
}

Prevention

When it happens

Trigger: Triggering a voice/TTS reply (e.g. a voice-reply command or voice output of a response) when no [tts] block is present in config.toml, or when tts.enabled = false.

Common situations: Users upgrading cc-connect and expecting voice replies without adding the [tts] config section; configs where TTS was intentionally disabled but a voice command is still issued; copying a config that omits TTS settings.

Related errors


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