{"record":{"id":"f570ce0f893b7d4c","repo":"siyuan-note/siyuan","slug":"assetpath-is-required-for-analyze","errorCode":null,"errorMessage":"assetPath is required for analyze","messagePattern":"assetPath is required for analyze","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/assets.go","lineNumber":382,"sourceCode":"\t\treturn DocumentImageList{}, fmt.Errorf(\"list document images failed: %w\", err)\n\t}\n\trefs := make([]ImageArtifactRef, 0, len(paths))\n\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)","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/assets.go#L364-L400","documentation":"Returned by PrepareDocumentImage when assetPath is empty after strings.TrimSpace. It is a pure input-validation guard emitted before any document lookup, file read, or model call. The message text (\"for analyze\") reflects the AI-vision use case this function was built for.","triggerScenarios":"Calling PrepareDocumentImage(documentID, \"\") or with a whitespace-only assetPath (e.g. \"   \"). Typically a caller that forgot to bind the path argument, passed an empty selection, or forwarded an unvalidated HTTP/JSON payload field.","commonSituations":"An AI tool or editor callback invokes PrepareDocumentImage with no currently-selected image; a JSON request body with a missing/null assetPath field deserialized to \"\"; a refactor that dropped the argument.","solutions":["Trim and check assetPath at the call site before invoking PrepareDocumentImage.","If the path comes from a request payload, return a 400 with a clear field-level message instead of letting it reach the kernel.","When the caller has no path yet, call ListDocumentImages first and let the user pick a path."],"exampleFix":"// before\nprepared, err := model.PrepareDocumentImage(docID, assetPath)\n\n// after\nassetPath = strings.TrimSpace(assetPath)\nif assetPath == \"\" {\n    return fmt.Errorf(\"assetPath must be provided\")\n}\nprepared, err := model.PrepareDocumentImage(docID, assetPath)","handlingStrategy":"validation","validationCode":"assetPath = strings.TrimSpace(assetPath)\nif assetPath == \"\" {\n    // return early, do not call PrepareDocumentImage\n    return errors.New(\"assetPath must be provided\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trim and check every user/JSON-supplied path field at the request boundary.","Make assetPath a required field in request DTOs so missing values fail fast in deserialization.","Use ListDocumentImages to obtain candidate paths so the caller never has an empty value to pass."],"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"}