siyuan-note/siyuan · error
document ID does not match path
Error message
document ID does not match path: %s
What it means
SiYuan requires that a document file's name equals the root block ID (filename is '<ID>.sy'). After parsing, if tree.Root.ID differs from the filename stem, the scan aborts because references would be attributed to the wrong block ID and downstream relinking/history would corrupt the index.
Solutions
- Rename the file back to '<RootID>.sy' matching the root ID in its JSON content.
- Or use the SiYuan app's duplicate/export features, which regenerate IDs, instead of copying files manually.
- If the document is a stray duplicate, delete it.
- After fixing, rerun the relink with dryRun=true to confirm the whole notebook scans cleanly.
Example fix
// before (shell) mv data/notebooks/xxx/20240101120000-abc.sy data/notebooks/xxx/my-note.sy // after (shell) mv data/notebooks/xxx/my-note.sy data/notebooks/xxx/20240101120000-abc.sy
Defensive patterns
Strategy: validation
Validate before calling
var hdr struct{ ID string `json:"ID"` }
json.Unmarshal(data, &hdr)
if hdr.ID != strings.TrimSuffix(filepath.Base(syPath), ".sy") {
return fmt.Errorf("ID/filename mismatch: %s", syPath)
} Prevention
- Never rename .sy files in a file manager
- Duplicate documents via the app so IDs regenerate
- Check filename == RootID after any manual restore
When it happens
Trigger: A .sy file was renamed on disk (manually or by a script) without updating the root ID inside the JSON, or the document was copied to a new filename while retaining the original ID; detected as tree.Root.ID != strings.TrimSuffix(entry.Name(), ".sy").
Common situations: Users renaming .sy files in a file manager to reorganize; duplicate-document scripts copying files without regenerating IDs; restoring backups under different filenames; git operations that renamed files.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- asset escapes its directory
- asset must be a regular file
- cannot parse document
- capability ID collision
- capability model name collision
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/7d70e1dc8ad36a0c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/asset_relink.go:198
}
titles[header.ID] = header.Properties.Title
if !p.mayContainReferences(data) && !bytes.Contains(data, []byte("NodeAttributeView")) {
return nil
}
p.parsedDocuments++
tree, readErr := dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)
if readErr != nil || tree == nil || tree.Root == nil {
return fmt.Errorf("cannot parse document %s: %v", absPath, readErr)
}
rel, _ := filepath.Rel(boxDir, absPath)
tree.Box, tree.Path = boxID, "/"+filepath.ToSlash(rel)
tree.Root.Box, tree.Root.Path = tree.Box, tree.Path
tree.HPath = "/" + tree.Root.IALAttr("title")
if readErr = filesys.NormalizeTreeForRead(tree); readErr != nil {
return readErr
}
if tree.Root.ID != strings.TrimSuffix(entry.Name(), ".sy") {
return fmt.Errorf("document ID does not match path: %s", absPath)
}
titles[tree.Root.ID] = tree.Root.IALAttr("title")
before := len(p.result.References)
p.tree(tree, apicontract.AssetReference{Notebook: boxID, RootID: tree.Root.ID, Path: tree.Path})
retain := false
if len(p.result.References) > before {
p.files = append(p.files, &assetRelinkFile{path: absPath, before: data, tree: tree, items: p.referenceItems(before)})
retain = true
}
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if entering && n.Type == ast.NodeAttributeView {
retain = true
}
return ast.WalkContinue
})
if retain {
p.trees = append(p.trees, tree)
}View on GitHub (pinned to 9f775e8a12)