siyuan-note/siyuan · error
save generated image failed: %w
Error message
save generated image failed: %w
What it means
Returned by GenerateDocumentImage when InsertAssetBytes(bt.RootID, ...) fails after a successful image generation. InsertAssetBytes looks up the block tree, computes the assets dir, mkdir's it, hashes/dedups, and writes the file. The error is wrapped with markImageExecutionUnknown because the image has already been generated (and may be billed) — the bytes exist in memory but could not be persisted.
Source
Thrown at kernel/model/assets.go:461
Data: generated.Data, MIMEType: generated.MIMEType, Extension: generated.Extension, RevisedPrompt: generated.RevisedPrompt,
}, nil
}
// GenerateDocumentImage 使用通用图片生成能力创建文档资源。
func GenerateDocumentImage(ctx context.Context, request GenerateDocumentImageRequest) (GenerateDocumentImageResult, error) {
bt, err := resolveMultimodalDocument(request.DocumentID)
if err != nil {
return GenerateDocumentImageResult{}, err
}
generated, err := GenerateImage(ctx, GenerateImageRequest{
Prompt: request.Prompt, Size: request.Size, Quality: request.Quality, OutputFormat: request.OutputFormat,
})
if err != nil {
return GenerateDocumentImageResult{}, err
}
assetPath, _, err := InsertAssetBytes(bt.RootID, "ai-image"+generated.Extension, generated.Data)
if err != nil {
return GenerateDocumentImageResult{}, markImageExecutionUnknown(fmt.Errorf("save generated image failed: %w", err))
}
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 {View on GitHub (pinned to 251596fc0d)
Solutions
- Free disk space and ensure util.DataDir is writable.
- Check the wrapped error: a 'block not found' (Conf.Language(71)) means the doc vanished mid-call — refresh the block tree and re-resolve.
- Do not retry blindly: the provider call already succeeded (IsImageExecutionUnknown is true); persist manually if you still have the bytes.
Example fix
// before
res, err := model.GenerateDocumentImage(ctx, req)
if err != nil { return err } // loses the generated bytes
// after — surface the unknown-execution nature to the user
res, err := model.GenerateDocumentImage(ctx, req)
if err != nil {
if model.IsImageExecutionUnknown(err) {
// image was generated but not saved; tell the user, offer re-save
return fmt.Errorf("image generated but save failed (you may be charged): %w", err)
}
return err
} Defensive patterns
Strategy: try-catch
Type guard
func isImageExecUnknown(err error) bool { return model.IsImageExecutionUnknown(err) } Try / catch
res, err := model.GenerateDocumentImage(ctx, req)
if err != nil {
if model.IsImageExecutionUnknown(err) {
// image was generated (possibly billed) but not saved — do not retry blindly
return fmt.Errorf("generation ok but save failed: %w", err)
}
return err
} Prevention
- Keep free disk space on the util.DataDir volume.
- Ensure the data directory is writable and not on a read-only mount.
- If save fails, tell the user the generation may have been billed — do not silently retry.
When it happens
Trigger: The block tree entry for the document disappeared between the resolveMultimodalDocument call and the InsertAssetBytes call; the assets directory cannot be created (read-only data dir, disk full); os.MkdirAll or writeAssetFile fails due to permissions or path length; the asset data is empty (shouldn't happen post-generation but is guarded).
Common situations: Disk full on the volume holding util.DataDir; data dir on a read-only mount; antivirus blocks the write on Windows; the doc was deleted in a concurrent operation.
Related errors
- failed to persist key backup: %w
- write data [%s] failed: %s
- save OAuth client registration: %w
- save OAuth credentials: %w
- read image failed: %w
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/0f589837dd0d3d37.
Report an issue: GitHub.