siyuan-note/siyuan · warning
asset path [%s] does not match data path [%s]
Error message
asset path [%s] does not match data path [%s]
What it means
When an asset request is resolved by dataPath, the handler converts the data-relative path back to the canonical asset path and requires that it equals the requested cleanPath. If they differ (or the conversion fails), the request is rejected. This is a safety check preventing a dataPath parameter from being used to smuggle access to a different file than the URL path names.
Source
Thrown at kernel/server/serve.go:994
if err != nil {
return false
}
_, validatedAbsPath, err := model.ResolveDataAssetPath(filepath.ToSlash(dataRelativePath))
return err == nil && filepath.Clean(validatedAbsPath) == filepath.Clean(assetAbsPath)
}
func resolveAssetRequestPath(cleanPath, boxID, dataPath string) (string, error) {
if dataPath != "" {
if boxID != "" {
return "", errors.New("box and dataPath cannot be used together")
}
dataRelativePath, assetAbsPath, err := model.ResolveDataAssetPath(dataPath)
if err != nil {
return "", err
}
assetPath, _, ok := model.AssetPathFromDataRelativePath(dataRelativePath)
if !ok || assetPath != cleanPath {
return "", fmt.Errorf("asset path [%s] does not match data path [%s]", cleanPath, dataPath)
}
return assetAbsPath, nil
}
if boxID != "" {
return model.GetAssetAbsPathInBox(cleanPath, boxID)
}
return model.GetAssetAbsPath(cleanPath)
}
func serveAssets(ginServer *gin.Engine) {
ginServer.POST("/upload", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, model.Upload)
ginServer.GET("/assets/*path", model.CheckAuth, func(context *gin.Context) {
requestPath := context.Param("path")
if "/" == requestPath || "" == requestPath {
// 禁止访问根目录 Disable HTTP access to the /assets/ path https://github.com/siyuan-note/siyuan/issues/15257
context.Status(http.StatusForbidden)
returnView on GitHub (pinned to 8641553a1f)
Solutions
- Make the URL path and the `dataPath` parameter refer to the same file (dataPath is workspace-data-relative, e.g. assets/foo.png)
- Regenerate the URL if the asset was moved or renamed
- If you only know the data-relative path, request the asset directly by that path without a conflicting URL path
- Do not attempt to reach files outside the data directory via dataPath — model.ResolveDataAssetPath validates and rejects path traversal separately
Example fix
// before GET /assets/wrong-name.png?dataPath=assets/correct-name.png // after GET /assets/correct-name.png?dataPath=assets/correct-name.png
Defensive patterns
Strategy: validation
Validate before calling
// client-side: ensure URL path and dataPath refer to the same file
const derived = dataPath.replace(/^assets\//, "");
if (derived !== name) throw new Error("URL path and dataPath must reference the same asset"); Try / catch
const res = await fetch(url);
if (!res.ok) {
const msg = await res.text();
if (msg.includes("does not match data path")) {
// regenerate URL from the canonical dataPath
}
} Prevention
- Derive the URL path from dataPath, never independently
- Regenerate asset URLs after moving or renaming files
- Do not use dataPath to reach files outside assets/ in the data dir
When it happens
Trigger: resolveAssetRequestPath called with dataPath set where model.AssetPathFromDataRelativePath(dataRelativePath) returns ok=false, or the derived assetPath differs from the cleanPath taken from the URL (kernel/server/serve.go:994). E.g. URL /assets/a.png with dataPath=/etc/passwd or with a dataPath pointing at another asset.
Common situations: Hand-crafted or proxied URLs where the path segment and dataPath were generated at different times; path manipulation attempts caught by the guard; assets moved/renamed so the dataPath no longer maps to the URL path.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- asset path must be relative to data directory: %s
- symlink [%s] resolves outside data/assets: [%s]
- path contains invalid character [%s]
- local asset path is not allowed
- box and dataPath cannot be used together
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/c96d3a08c6169e0d.
Report an issue: GitHub.