siyuan-note/siyuan · error
image model is not configured
Error message
image model is not configured
What it means
validateImageModel checks that both the resolved AI provider (conf.Provider) and the image-generation model (conf.Model) are non-nil. If either is missing — meaning no image-generation provider/model is configured in Settings - AI — it returns "image model is not configured". It then also validates the provider protocol.
Solutions
- Open Settings - AI - Image generation and select a provider and model, then save
- Verify Conf.AI.ImageGeneration has a valid provider with API key and an image-capable model name
- In code, check Conf.AI.GetImageGenerationModel() for nil before calling GenerateImage to give a friendlier message
- Re-add the provider entry if the referenced provider was removed from the provider list
Example fix
// before
provider, m := conf.Conf.AI.GetImageGenerationModel() // nil, nil
result, err := model.GenerateImage(ctx, req)
// after
provider, m := conf.Conf.AI.GetImageGenerationModel()
if provider == nil || m == nil { return errors.New("configure an image model in Settings - AI first") }
result, err = model.GenerateImage(ctx, req) Defensive patterns
Strategy: validation
Validate before calling
provider, m := conf.Conf.AI.GetImageGenerationModel()
if provider == nil || m == nil {
return errors.New("select an image generation provider and model in Settings - AI first")
} Type guard
func imageModelConfigured() bool {
p, m := conf.Conf.AI.GetImageGenerationModel()
return p != nil && m != nil && p.APIKey != ""
} Try / catch
res, err := model.GenerateImage(ctx, req)
if err != nil && err.Error() == "image model is not configured" {
// direct the user to Settings - AI - Image generation instead of retrying
} Prevention
- Configure an image generation model before calling any GenerateImage path
- After provider changes, confirm the image model still resolves to an existing provider
- Add a startup check that logs when no image model is configured
When it happens
Trigger: Conf.AI.GetImageGenerationModel() returns nil provider or nil model because the user never selected an image generation model, the configured provider was deleted, or the model list failed to load; calling GenerateImage on a fresh installation with default (empty) AI settings.
Common situations: Fresh install with no AI configuration; user configured a chat model but not an image model; config synced from a machine where the image model pointed to a provider that no longer exists; API key removed leaving the provider entry incomplete.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- unsupported multimodal provider protocol
- AI configuration is unavailable
- generate image failed
- no AI editing config
- no AI editing model configured
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/be871133f0768e14.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/assets.go:589
return GenerateDocumentImageResult{
Artifact: ImageArtifactRef{
Kind: "image", Path: assetPath, MIMEType: generated.MIMEType, DocumentID: bt.RootID,
},
RevisedPrompt: generated.RevisedPrompt,
}, nil
}
func resolveMultimodalDocument(documentID string) (*treenode.BlockTree, error) {
bt := treenode.GetBlockTree(strings.TrimSpace(documentID))
if bt == nil {
return nil, errors.New("document not found: " + documentID)
}
return bt, nil
}
func validateImageModel(provider *conf.Provider, imageModel *conf.Model) error {
if provider == nil || imageModel == nil {
return errors.New("image model is not configured")
}
if provider.Protocol != "" && provider.Protocol != util.OpenAIProtocolChatCompletions &&
provider.Protocol != util.OpenAIProtocolResponses {
return fmt.Errorf("unsupported multimodal provider protocol: %s", provider.Protocol)
}
return nil
}
func documentReferencesImage(rootID, assetPath string) bool {
paths, err := DocImageAssets(rootID)
if err != nil {
return false
}
wanted := AssetPathWithoutQuery(assetPath)
for _, current := range paths {
if AssetPathWithoutQuery(current) == wanted {
return true
}View on GitHub (pinned to 9f775e8a12)