{"record":{"id":"7518802bbe03804b","repo":"sipeed/picoclaw","slug":"tts-provider-is-not-configured","errorCode":null,"errorMessage":"tts provider is not configured","messagePattern":"tts provider is not configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/tts/tts.go","lineNumber":99,"sourceCode":"\t\t\t\treturn provider\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// SynthesizeAndStore synthesizes text to speech and registers it in the media store, returning the media reference.\nfunc SynthesizeAndStore(\n\tctx context.Context,\n\tprovider TTSProvider,\n\tstore media.MediaStore,\n\ttext string,\n\tfilename string,\n\tchannel string,\n\tchatID string,\n) (string, error) {\n\tif provider == nil {\n\t\treturn \"\", fmt.Errorf(\"tts provider is not configured\")\n\t}\n\tif store == nil {\n\t\treturn \"\", fmt.Errorf(\"media store not configured\")\n\t}\n\tif channel == \"\" || chatID == \"\" {\n\t\treturn \"\", fmt.Errorf(\"no target channel/chat available\")\n\t}\n\tif strings.TrimSpace(text) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"text is required\")\n\t}\n\n\tstream, err := provider.Synthesize(ctx, text)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"tts synthesize failed: %w\", err)\n\t}\n\tdefer stream.Close()\n\n\terr = os.MkdirAll(media.TempDir(), 0o700)","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/tts/tts.go#L81-L117","documentation":"Returned by tts.SynthesizeAndStore when the provider argument is nil. The provider normally comes from DetectTTS(cfg), which returns nil when cfg is nil, Voice.TTSModelName is unset or unresolvable, and no ModelList entry both contains 'tts' in its model name and has an API key. This is a configuration/startup error, not a runtime fault.","triggerScenarios":"Voice features invoked with no TTS model configured; TTSModelName pointing at a model whose APIKey() is empty (providerFromModelConfig returns nil); model entries renamed so the 'tts' substring match in DetectTTS fails.","commonSituations":"Fresh installs without TTS config; renaming model entries; forgetting the api_key on the TTS model entry.","solutions":["Set voice.tts_model_name to a configured model that has an api_key","Or add a ModelList entry whose model name contains 'tts' (e.g. tts-1, mimo-v2-tts) with its api_key","Check DetectTTS(cfg) for nil right after startup and log a clear message","Skip TTS-dependent features when the provider is nil instead of calling SynthesizeAndStore"],"exampleFix":"// before\nref, err := tts.SynthesizeAndStore(ctx, provider, store, text, name, ch, id)\n// after\nif provider == nil {\n    logger.WarnF(`tts disabled: no provider detected`, nil)\n    return ``, nil\n}\nref, err := tts.SynthesizeAndStore(ctx, provider, store, text, name, ch, id)","handlingStrategy":"validation","validationCode":"provider := tts.DetectTTS(cfg)\nif provider == nil {\n    return errors.New(`no tts provider detected: set voice.tts_model_name or add a model containing 'tts' with an api_key`)\n}","typeGuard":"func isNotConfigured(err error) bool {\n    return err != nil && strings.Contains(err.Error(), `not configured`)\n}","tryCatchPattern":"if err != nil && isNotConfigured(err) {\n    // disable voice output for this session; do not retry until configuration changes\n}","preventionTips":["Run DetectTTS at startup and log whether a provider was found","Name TTS model entries so they contain 'tts' and always attach an api_key","Re-verify config after renaming model entries"],"tags":["configuration","tts","initialization"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}