{"record":{"id":"81eaf1ad0fc8d435","repo":"siyuan-note/siyuan","slug":"asset-path-is-required","errorCode":null,"errorMessage":"asset path is required","messagePattern":"asset path is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/assets.go","lineNumber":1025,"sourceCode":"\t\tsort.Slice(ret, func(i, j int) bool {\n\t\t\treturn ret[i].Updated > ret[j].Updated\n\t\t})\n\t}\n\n\tif Conf.Search.Limit <= len(ret) {\n\t\tret = ret[:Conf.Search.Limit]\n\t}\n\treturn\n}\n\nfunc GetAssetAbsPath(relativePath string) (string, error) {\n\treturn GetAssetAbsPathWithOpt(relativePath, false)\n}\n\n// ResolveDataAssetPath 解析 data 相对资源路径，并确保目标位于全局或普通笔记本的资源目录中。\nfunc ResolveDataAssetPath(assetPath string) (relativePath, absPath string, err error) {\n\tif assetPath == \"\" {\n\t\terr = errors.New(\"asset path is required\")\n\t\treturn\n\t}\n\n\tnativePath := filepath.FromSlash(assetPath)\n\tif filepath.IsAbs(nativePath) || filepath.VolumeName(nativePath) != \"\" ||\n\t\t(len(nativePath) > 0 && os.IsPathSeparator(nativePath[0])) {\n\t\terr = fmt.Errorf(\"asset path must be relative to data directory: %s\", assetPath)\n\t\treturn\n\t}\n\n\tnativePath = filepath.Clean(nativePath)\n\tabsPath = filepath.Join(util.DataDir, nativePath)\n\tdataRelativePath, relErr := filepath.Rel(util.DataDir, absPath)\n\tif relErr != nil || dataRelativePath == \".\" || dataRelativePath == \"..\" ||\n\t\tstrings.HasPrefix(dataRelativePath, \"..\"+string(filepath.Separator)) {\n\t\terr = fmt.Errorf(\"asset path escapes data directory: %s\", assetPath)\n\t\treturn\n\t}","sourceCodeStart":1007,"sourceCodeEnd":1043,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/assets.go#L1007-L1043","documentation":"ResolveDataAssetPath resolves a data-relative asset path to an absolute path, ensuring the target lies inside a valid assets directory (global assets/ or a notebook's assets/). It first rejects an empty input, since there is nothing to resolve. This is a guard against callers passing an unset or blank path variable.","triggerScenarios":"Calling ResolveDataAssetPath(\"\") directly, or via callers such as assetStat, deferredAssetPathFromFiles, PrepareAgentMessageImage, or ResolveUnusedDataAssetPath when the upstream path value was never populated (e.g. an agent message image with no path, or a missing query/form parameter).","commonSituations":"A plugin or API client omits the path parameter in an asset-related API request; a script variable holding the asset path is empty because an earlier lookup failed silently; agent message preparation receives an image entry without a path.","solutions":["Supply a non-empty data-relative asset path, e.g. \"assets/foo-20240101120000.png\" or \"<notebookID>/assets/img.png\"","Check where the path value originates and fix the upstream code/parameter so the path is populated before the call","For API callers, include the required path field in the request payload and validate it client-side before sending"],"exampleFix":"// before\nrel, abs, err := model.ResolveDataAssetPath(assetPath) // assetPath == \"\"\n// after\nif assetPath == \"\" {\n    return errors.New(\"caller must supply an asset path\")\n}\nrel, abs, err := model.ResolveDataAssetPath(assetPath)","handlingStrategy":"validation","validationCode":"if assetPath == \"\" {\n    return errors.New(\"asset path must be provided\")\n}","typeGuard":"func hasAssetPath(p string) bool { return strings.TrimSpace(p) != \"\" }","tryCatchPattern":"rel, abs, err := model.ResolveDataAssetPath(p)\nif err != nil {\n    if err.Error() == \"asset path is required\" {\n        return fmt.Errorf(\"no asset path supplied for %q operation\", op)\n    }\n    return err\n}","preventionTips":["Validate request parameters at the API boundary before calling asset helpers","Fail fast where the path is produced (e.g. check the result of the lookup that yields the path)","Avoid storing asset paths in variables that can be silently zero-valued; initialize with a sentinel and check"],"tags":["assets","validation","empty-path"],"backgroundTag":"empty-required-field","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}