siyuan-note/siyuan · error
asset path must be relative to data directory: %s
Error message
asset path must be relative to data directory: %s
What it means
Returned by ResolveDataAssetPath when the path is absolute, has a Windows volume name (C:), or begins with a path separator. ResolveDataAssetPath only accepts paths relative to util.DataDir; absolute inputs are rejected as the first anti-traversal layer. The offending path is interpolated.
Source
Thrown at kernel/model/assets.go:900
}
return
}
func GetAssetAbsPath(relativePath string) (string, error) {
return GetAssetAbsPathWithOpt(relativePath, false)
}
// ResolveDataAssetPath 解析 data 相对资源路径,并确保目标位于全局或普通笔记本的资源目录中。
func ResolveDataAssetPath(assetPath string) (relativePath, absPath string, err error) {
if assetPath == "" {
err = errors.New("asset path is required")
return
}
nativePath := filepath.FromSlash(assetPath)
if filepath.IsAbs(nativePath) || filepath.VolumeName(nativePath) != "" ||
(len(nativePath) > 0 && os.IsPathSeparator(nativePath[0])) {
err = fmt.Errorf("asset path must be relative to data directory: %s", assetPath)
return
}
nativePath = filepath.Clean(nativePath)
absPath = filepath.Join(util.DataDir, nativePath)
dataRelativePath, relErr := filepath.Rel(util.DataDir, absPath)
if relErr != nil || dataRelativePath == "." || dataRelativePath == ".." ||
strings.HasPrefix(dataRelativePath, ".."+string(filepath.Separator)) {
err = fmt.Errorf("asset path escapes data directory: %s", assetPath)
return
}
parts := strings.Split(filepath.ToSlash(dataRelativePath), "/")
assetDirIndex := -1
switch {
case len(parts) > 1 && parts[0] == "assets":
assetDirIndex = 0
case len(parts) > 2 && ast.IsNodeIDPattern(parts[0]):View on GitHub (pinned to 251596fc0d)
Solutions
- Strip leading slashes and volume names at the call site, or reject them with a 400.
- Only ever pass data-directory-relative paths (e.g. "assets/x.png" or "<boxID>/assets/x.png").
Example fix
// before
rel, abs, err := model.ResolveDataAssetPath("/data/assets/x.png")
// after — pass a data-relative path
rel, abs, err := model.ResolveDataAssetPath("assets/x.png") Defensive patterns
Strategy: validation
Validate before calling
np := filepath.FromSlash(assetPath)
if filepath.IsAbs(np) || filepath.VolumeName(np) != "" || (len(np) > 0 && os.IsPathSeparator(np[0])) {
return fmt.Errorf("asset path must be data-relative: %s", assetPath)
} Prevention
- Always pass data-directory-relative paths to ResolveDataAssetPath.
- Strip leading separators and volume names from any user-supplied input upstream.
- Treat absolute paths from clients as malformed, not as a convenience.
When it happens
Trigger: Passing "/etc/passwd", "C:\\Windows\\x", "/home/user/data/assets/x.png", or any leading-"/" path. These would bypass the data-dir containment if joined naively.
Common situations: A client sends a full filesystem path instead of a data-relative one; a debug tooling path leaks through; an attempt at path traversal via absolute path.
Related errors
- asset path escapes data directory: %s
- path is not a child of assets directory: %s
- [%s] is not an asset path
- [%s] is not an asset path (must start with assets/)
- path escapes templates dir: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/aab882f460cda625.
Report an issue: GitHub.