{"record":{"id":"a64c3156762bd1ea","repo":"siyuan-note/siyuan","slug":"no-ai-editing-model-configured","errorCode":null,"errorMessage":"no AI editing model configured","messagePattern":"no AI editing model configured","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/ai.go","lineNumber":162,"sourceCode":"\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}\n\n\tmessages := buildAIEditorMessages(prompt, history, editing.MaxHistoryMessages)\n\n\treq := openai.ChatCompletionRequest{\n\t\tModel:               m.Name,","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/ai.go#L144-L180","documentation":"After confirming some provider exists, NewAIEditorChatStream (kernel/model/ai.go:162) calls Conf.AI.GetEditingModel(); if it returns a nil provider or nil model the AI editor has no model to send requests to and the constructor aborts. This happens when the dedicated editing model was never selected, or the selected model's provider/model no longer exists in configuration.","triggerScenarios":"AI editor request when the editing model field is empty, or when it still points at a model whose provider was deleted or renamed. Distinct from error 363: providers exist, but none is bound as the editing model.","commonSituations":"Users who configured a chat model but never picked the separate editing model; deleting or renaming a provider while the editing-model reference still points at it; config restored from an older backup.","solutions":["Open 设置 - 人工智能 and explicitly select an editing model (编辑模型), then save","If the previously selected model's provider was removed, re-add the provider or re-select a model that currently exists","Retry the AI editor action after saving"],"exampleFix":"// before: providers configured but editingModel unset -> \"no AI editing model configured\"\n// after: in 设置 - 人工智能 choose Editing model = \"gpt-4o-mini\" (an existing provider model), save, retry","handlingStrategy":"validation","validationCode":"if prov, m := Conf.AI.GetEditingModel(); prov == nil || m == nil {\n    // editing model not selected or dangling: block the action and prompt setup\n    promptSelectEditingModel()\n    return\n}","typeGuard":null,"tryCatchPattern":"if err != nil && err.Error() == \"no AI editing model configured\" {\n    openAISettings(section: \"editing-model\")\n    return\n}","preventionTips":["After adding a provider, immediately select both chat and editing models","When deleting a provider, also clear model references that point at it","Validate the editing-model reference after restoring config backups"],"tags":["ai","configuration","model-selection"],"backgroundTag":"missing-configuration","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}