{"record":{"id":"f0c4115eed1a6351","repo":"sipeed/picoclaw","slug":"media-store-not-configured","errorCode":null,"errorMessage":"media store not configured","messagePattern":"media store not configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/tts/tts.go","lineNumber":102,"sourceCode":"\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)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create media temp dir: %w\", err)\n\t}","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/tts/tts.go#L84-L120","documentation":"Returned by tts.SynthesizeAndStore when the media.MediaStore argument is nil — the media subsystem was not wired into the TTS call path. Synthesis is skipped entirely; nothing is written to disk or registered.","triggerScenarios":"Calling SynthesizeAndStore with a nil store handle: the media store was never initialized, or a new call site forgot to pass it.","commonSituations":"New integrations adding TTS to another channel without plumbing the media store; tests that stub the store as nil.","solutions":["Initialize the media store at startup and pass the same instance used by other media features","Guard call sites: skip TTS when the store is nil and log why","In tests, use an in-memory store implementation instead of nil"],"exampleFix":"// before\nref, err := tts.SynthesizeAndStore(ctx, p, nil, text, name, ch, id)\n// after\nif store == nil {\n    return ``, errors.New(`media store unavailable; skipping tts`)\n}\nref, err := tts.SynthesizeAndStore(ctx, p, store, text, name, ch, id)","handlingStrategy":"validation","validationCode":"if store == nil {\n    return errors.New(`media store not initialized; tts output cannot be registered`)\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    // wiring bug at the call site: skip tts and alert, no retry will help\n}","preventionTips":["Initialize the media store once at startup and inject it everywhere","Nil-check the store at every new TTS call site","Use an in-memory store in tests instead of nil"],"tags":["configuration","media","tts","null-check"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}