{"record":{"id":"5051fd5d1568a288","repo":"siyuan-note/siyuan","slug":"no-ai-provider-configured","errorCode":null,"errorMessage":"no AI provider configured","messagePattern":"no AI provider configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/ai.go","lineNumber":157,"sourceCode":"\nfunc (stream *AIEditorChatStream) Recv() (response openai.ChatCompletionStreamResponse, err error) {\n\ttimer, timerDone := startAIEditorCancelTimer(stream.idleTimeout, stream.cancel)\n\tresponse, err = stream.stream.Recv()\n\tif stopAIEditorCancelTimer(timer, timerDone) {\n\t\terr = errors.New(\"AI editor stream idle timeout\")\n\t}\n\treturn\n}\n\nfunc (stream *AIEditorChatStream) Close() {\n\tstream.cancel()\n\tstream.stream.Close()\n}\n\n// NewAIEditorChatStream 创建绑定到编辑器请求生命周期的模型流。\nfunc NewAIEditorChatStream(ctx context.Context, ids []string, input, action string, history []AIEditorMessage) (*AIEditorChatStream, error) {\n\tif !Conf.AI.HasAnyProvider() {\n\t\treturn nil, errors.New(\"no AI provider configured\")\n\t}\n\n\tprov, m := Conf.AI.GetEditingModel()\n\tif nil == prov || nil == m {\n\t\treturn nil, errors.New(\"no AI editing model configured\")\n\t}\n\tediting := Conf.AI.Editing\n\tif nil == editing {\n\t\treturn nil, errors.New(\"no AI editing config\")\n\t}\n\n\tif \"\" == input && 0 < len(ids) {\n\t\tinput = getBlocksContent(ids)\n\t}\n\tprompt := BuildAIEditorPrompt(input, action)\n\tif \"\" == strings.TrimSpace(prompt) {\n\t\treturn nil, errors.New(\"AI editor input is empty\")\n\t}","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/ai.go#L139-L175","documentation":"NewAIEditorChatStream first verifies that at least one AI provider is configured (Conf.AI.HasAnyProvider()); if none is, it returns this error without creating the stream. The editor AI chat feature requires an API provider (e.g. OpenAI-compatible endpoint with key) to be set up in configuration.","triggerScenarios":"Calling the aiEditorChat contract endpoint (editor AI chat) when no AI providers exist in the configuration — empty provider list, fresh install, or providers removed/cleared.","commonSituations":"Fresh SiYuan install where AI settings were never filled in, API key cleared or config reset, sync restoring a config without AI settings, calling the editor AI API from a plugin/automation on a machine without AI setup.","solutions":["Open Settings - AI and add at least one AI provider (endpoint + API key)","Verify the configuration file actually contains AI provider entries (Conf.AI.Providers non-empty)","If calling programmatically, check Conf.AI.HasAnyProvider() (or fetch AI config via API) before invoking the editor chat endpoint","Re-enter the API key if an upgrade or config merge dropped it"],"exampleFix":"// before\nstream, err := model.NewAIEditorChatStream(ctx, ids, input, action, history) // fails: no provider\n// after\nif !conf.AI.HasAnyProvider() {\n    return errors.New(\"please configure an AI provider in Settings - AI first\")\n}\nstream, err := model.NewAIEditorChatStream(ctx, ids, input, action, history)","handlingStrategy":"validation","validationCode":"// before invoking editor AI chat\nconst aiConf = await fetchPost('/api/ai/...', {});\nif (!aiConf || !aiConf.ai || !aiConf.ai.providers || aiConf.ai.providers.length === 0) {\n  alert('Please configure an AI provider in Settings - AI first');\n  return;\n}","typeGuard":"null","tryCatchPattern":"try {\n  stream, err := model.NewAIEditorChatStream(ctx, ids, input, action, history)\n  if err != nil { return err } // includes \"no AI provider configured\"\n} catch (e) { showAiSetupDialog(); }","preventionTips":["Set up at least one AI provider (endpoint + key) before using editor AI features","Surface a setup dialog instead of the raw error in UI code","Check provider presence programmatically when automating via the API","Back up AI settings across config resets/syncs"],"tags":["ai","configuration","mcp","missing-provider"],"backgroundTag":"missing-api-key","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}