siyuan-note/siyuan · warning
local asset path is not allowed
Error message
local asset path is not allowed
What it means
When inserting assets from an HTML context (validateHTMLPath is true, i.e. InsertHTMLLocalAssets), each absolute path is screened with util.IsSensitivePath and EncryptedRawPathBoxID. Paths deemed sensitive (e.g. pointing into system/config locations) or located inside an encrypted notebook's raw storage are rejected with "local asset path is not allowed" and skipped as a per-file failure.
Source
Thrown at kernel/model/upload.go:174
return
}
boxID = bt.BoxID
docDirLocalPath := filepath.Join(util.DataDir, boxID, path.Dir(bt.Path))
assetsDirPath = getAssetsDir(filepath.Join(util.DataDir, boxID), docDirLocalPath)
}
if !gulu.File.IsExist(assetsDirPath) {
if err = os.MkdirAll(assetsDirPath, 0755); err != nil {
return
}
}
for index, assetAbsPath := range assetAbsPaths {
if strings.HasPrefix(strings.ToLower(assetAbsPath), "file://") {
assetAbsPath = util.FileURLToLocalPath(assetAbsPath)
}
baseName := filepath.Base(assetAbsPath)
if validateHTMLPath && (util.IsSensitivePath(assetAbsPath) || EncryptedRawPathBoxID(assetAbsPath) != "") {
recordAssetUploadFailure(&failedFiles, index, baseName, errors.New("local asset path is not allowed"))
continue
}
fName := baseName
fName = util.FilterUploadFileName(fName)
ext := filepath.Ext(fName)
fName = strings.TrimSuffix(fName, ext)
ext = strings.ToLower(ext)
fName += ext
if gulu.File.IsDir(assetAbsPath) || !isUpload {
if !strings.HasPrefix(assetAbsPath, "\\\\") {
assetAbsPath = "file://" + assetAbsPath
}
recordAssetUploadSuccess(succMap, &succFiles, index, baseName, assetAbsPath)
continue
}
if gulu.File.IsSubPath(assetsDirPath, assetAbsPath) {
// 已经位于 assets 目录下的资源文件不处理View on GitHub (pinned to 8641553a1f)
Solutions
- Copy the file to a normal, non-sensitive location (e.g. a temp directory) and insert from there.
- Check the path with util.IsSensitivePath before calling; skip or relocate files inside encrypted notebook raw storage.
- Use the standard Upload API (multipart form) instead of local-path insertion for files originating from protected locations.
Example fix
// before
model.InsertHTMLLocalAssets(docID, []string{"/workspace/data/encrypted-box/raw/image.png"})
// after
tmp := filepath.Join(os.TempDir(), "image.png")
copyFile(tmp, "/workspace/data/encrypted-box/raw/image.png")
model.InsertHTMLLocalAssets(docID, []string{tmp}) Defensive patterns
Strategy: validation
Validate before calling
func insertableHTMLAsset(p string) bool {
if strings.HasPrefix(strings.ToLower(p), "file://") {
p = util.FileURLToLocalPath(p)
}
return !util.IsSensitivePath(p) && model.EncryptedRawPathBoxID(p) == ""
} Try / catch
_, _, failed, err := model.InsertHTMLLocalAssets(docID, paths)
for _, f := range failed {
if f.Error == "local asset path is not allowed" {
// copy to temp and retry that single file
tmp := copyToTemp(paths[f.Index])
model.InsertHTMLLocalAssets(docID, []string{tmp})
}
} Prevention
- Never reference files inside the workspace's protected or encrypted raw directories in HTML.
- Stage external files in a plain temp/user directory before inserting.
- Screen every path with util.IsSensitivePath during development of paste/clipper flows.
When it happens
Trigger: Calling InsertHTMLLocalAssets with a file:// URL or absolute path that resolves to a sensitive path (per util.IsSensitivePath), or a path inside an encrypted notebook's raw data area; HTML paste/drop flows referencing such locations.
Common situations: Pasting HTML whose embedded images point at restricted local paths; browser-clipper or automation flows supplying paths under the workspace's protected directories; attempting to re-import a file that lives inside an encrypted box's raw storage.
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]
- asset path [%s] does not match data path [%s]
- invalid archive entry path [%s]
- archive entry resolves outside destination [%s]
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/e364334ae1c7306d.
Report an issue: GitHub.