{"record":{"id":"353fc09ca2dfcf24","repo":"siyuan-note/siyuan","slug":"s-is-not-sub-path-of-workspace","errorCode":null,"errorMessage":"[%s] is not sub path of workspace","messagePattern":"\\[(.+?)\\] is not sub path of workspace","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/assets.go","lineNumber":1097,"sourceCode":"\trelativePath = path.Clean(relativePath)\n\tif relativePath == \".\" || strings.HasPrefix(relativePath, \"../\") || relativePath == \"..\" || path.IsAbs(relativePath) {\n\t\treturn \"\", fmt.Errorf(\"[%s] is not an asset path\", relativePath)\n\t}\n\tif !strings.HasPrefix(relativePath, \"assets/\") {\n\t\treturn \"\", fmt.Errorf(\"[%s] is not an asset path (must start with assets/)\", relativePath)\n\t}\n\tif boxID != \"\" && !ast.IsNodeIDPattern(boxID) {\n\t\treturn \"\", fmt.Errorf(\"[%s] is not a box id\", boxID)\n\t}\n\n\tif boxID == \"\" {\n\t\treturn GetAssetAbsPathWithOpt(relativePath, false)\n\t}\n\n\tp := filepath.Join(util.DataDir, boxID, relativePath)\n\tif gulu.File.IsExist(p) {\n\t\tif !gulu.File.IsSubPath(util.WorkspaceDir, p) {\n\t\t\treturn \"\", fmt.Errorf(\"[%s] is not sub path of workspace\", p)\n\t\t}\n\t\t// 解析符号链接/目录联接，防止软链接跳出资产根目录\n\t\tif realP, evalErr := filepath.EvalSymlinks(p); evalErr == nil && realP != p {\n\t\t\tif !gulu.File.IsSubPath(util.WorkspaceDir, realP) {\n\t\t\t\treturn \"\", fmt.Errorf(\"symlink [%s] resolves outside workspace: [%s]\", p, realP)\n\t\t\t}\n\t\t\t// 验证解析后的路径仍在 <boxID>/assets/ 或全局 data/assets/ 下\n\t\t\texpectedPrefix := filepath.Join(util.DataDir, \"assets\")\n\t\t\tif boxID != \"\" {\n\t\t\t\texpectedPrefix = filepath.Join(util.DataDir, boxID, \"assets\")\n\t\t\t}\n\t\t\tif !gulu.File.IsSubPath(expectedPrefix, realP) {\n\t\t\t\treturn \"\", fmt.Errorf(\"symlink [%s] resolves outside assets directory: [%s]\", p, realP)\n\t\t\t}\n\t\t}\n\t\treturn p, nil\n\t}\n\t// 非加密 box 的资源可能回退到全局 data/assets（兼容旧笔记本结构）","sourceCodeStart":1079,"sourceCodeEnd":1115,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/assets.go#L1079-L1115","documentation":"Thrown by GetAssetAbsPathInBox (kernel/model/assets.go:1097) in the box-scoped branch: after joining `DataDir/boxID/relativePath` into `p` and confirming the file exists, it checks that `p` is still inside util.WorkspaceDir. This catches cases where DataDir/boxID have been manipulated (e.g. via symlinked workspace roots) such that the lexical join leaves the workspace.","triggerScenarios":"Calling GetAssetAbsPathInBox with a valid-looking boxID and `assets/...` path where the resulting real directory lives outside WorkspaceDir — for instance WorkspaceDir is a symlink and DataDir resolves elsewhere, or the workspace was reconfigured so DataDir is no longer under WorkspaceDir.","commonSituations":"Custom workspace setups where --workspace points at a directory but DataDir was overridden (env/workspace config) to live outside it; misconfigured portable deployments; symlinked workspace root that was later moved.","solutions":["Verify util.DataDir is configured to live inside util.WorkspaceDir (this is the supported layout).","Check for and remove any symlink on the workspace or data directory that points outside WorkspaceDir.","Restart the kernel with a clean --workspace so DataDir is recomputed under the workspace.","If you intentionally separate data and workspace, note this is unsupported and will keep tripping the guard."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Assert the supported layout before resolving box assets.\nif !gulu.File.IsSubPath(util.WorkspaceDir, util.DataDir) {\n    return errors.New(\"DataDir must live inside WorkspaceDir\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := model.GetAssetAbsPathInBox(ref, box); err != nil && strings.Contains(err.Error(), \"is not sub path of workspace\") {\n    // workspace/data layout misconfiguration; fix --workspace rather than retry\n}","preventionTips":["Keep DataDir inside WorkspaceDir (the only supported layout).","Do not symlink the workspace or data dir to external locations.","Run a clean --workspace if the layout was changed."],"tags":["assets","workspace","security","filesystem","configuration"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}