{"record":{"id":"218881f0ff94a794","repo":"siyuan-note/siyuan","slug":"only-local-assets-images-are-supported","errorCode":null,"errorMessage":"only local assets/... images are supported","messagePattern":"only local assets/\\.\\.\\. images are supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/assets.go","lineNumber":385,"sourceCode":"\tseen := map[string]bool{}\n\tfor _, assetPath := range paths {\n\t\tif !strings.HasPrefix(AssetPathWithoutQuery(assetPath), \"assets/\") || seen[assetPath] {\n\t\t\tcontinue\n\t\t}\n\t\tseen[assetPath] = true\n\t\trefs = append(refs, ImageArtifactRef{Kind: \"image\", Path: assetPath, DocumentID: bt.RootID})\n\t}\n\treturn DocumentImageList{DocumentID: bt.RootID, Images: refs}, nil\n}\n\n// PrepareDocumentImage 校验并读取文档实际引用的本地资源图片，供当前模型直接接收图片输入。\nfunc PrepareDocumentImage(documentID, assetPath string) (PreparedDocumentImage, error) {\n\tassetPath = strings.TrimSpace(assetPath)\n\tif assetPath == \"\" {\n\t\treturn PreparedDocumentImage{}, errors.New(\"assetPath is required for analyze\")\n\t}\n\tif !strings.HasPrefix(AssetPathWithoutQuery(assetPath), \"assets/\") {\n\t\treturn PreparedDocumentImage{}, errors.New(\"only local assets/... images are supported\")\n\t}\n\tbt, err := resolveMultimodalDocument(documentID)\n\tif err != nil {\n\t\treturn PreparedDocumentImage{}, err\n\t}\n\tif !documentReferencesImage(bt.RootID, assetPath) {\n\t\treturn PreparedDocumentImage{}, errors.New(\"assetPath is not an image referenced by the document\")\n\t}\n\tdata, err := ReadAssetBytesInBox(bt.BoxID, assetPath)\n\tif err != nil {\n\t\treturn PreparedDocumentImage{}, fmt.Errorf(\"read image failed: %w\", err)\n\t}\n\tprepared, err := util.PrepareModelImage(\n\t\tdata, documentImageMaxBytes, documentImageMaxPixels, documentImageMaxEdge,\n\t)\n\tif err != nil {\n\t\treturn PreparedDocumentImage{}, err\n\t}","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/assets.go#L367-L403","documentation":"Returned by PrepareDocumentImage when AssetPathWithoutQuery(assetPath) does not have the prefix \"assets/\". Only local in-doc assets are eligible for model image input; remote URLs, absolute filesystem paths, and non-assets paths are rejected up front.","triggerScenarios":"Passing a network URL (http/https), an absolute path (/home/x/y.png), a relative path outside assets/ (../foo.png), or a path with a leading slash. The check strips any ?query before testing the prefix, so ?box=... suffixes on encrypted-notebook assets are still allowed — only the prefix is rejected.","commonSituations":"A user pastes a remote image URL expecting it to be analyzed; a caller passes the full disk path instead of the doc-relative assets/... form; a migrated doc still references an old path scheme.","solutions":["Only pass paths in the form \"assets/<filename>\" (optionally with \"?box=<boxID>\" for encrypted notebooks).","For remote images, first download them into the document's assets/ directory via the upload API, then call PrepareDocumentImage.","Use ListDocumentImages to obtain paths guaranteed to be in the accepted form."],"exampleFix":"// before — caller passes a remote URL\nprepared, err := model.PrepareDocumentImage(docID, \"https://example.com/a.png\")\n\n// after — caller downloads into assets/ first, then uses the local path\nprepared, err := model.PrepareDocumentImage(docID, \"assets/a-20260101000000.png\")","handlingStrategy":"validation","validationCode":"clean := model.AssetPathWithoutQuery(strings.TrimSpace(assetPath))\nif !strings.HasPrefix(clean, \"assets/\") {\n    return fmt.Errorf(\"asset path must be local assets/... form, got %q\", assetPath)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["For remote images, download to the doc's assets/ dir first via the upload API.","Never pass absolute filesystem paths or URLs to PrepareDocumentImage.","Reuse paths emitted by ListDocumentImages — they are already in the accepted form."],"tags":["validation","assets","input-validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}