siyuan-note/siyuan · error
invalid document JSON
Error message
invalid document JSON: %s
What it means
The scan reads each .sy document and validates that its content is well-formed JSON via json.Valid(data) (after the spec check). If the bytes are not valid JSON, the document is corrupt or not a SiYuan document, and the scan aborts with the absolute path rather than silently skipping a potentially referenced document.
Solutions
- Inspect the reported .sy file: repair or restore it from a snapshot/history backup or file history.
- If the document is unwanted, remove it from the notebook so the scan can proceed.
- Re-run relinking with dryRun=true after fixing to confirm the whole tree parses.
- Restore the workspace from sync or local history if multiple documents are corrupted.
- Never hand-edit .sy JSON without validating afterward (e.g. with a JSON linter).
Example fix
// before (terminal) cat data/notebooks/xxx/20240101120000-abc.sy # truncated JSON // after (terminal) cp .siyuan/history/.../20240101120000-abc.sy data/notebooks/xxx/20240101120000-abc.sy
Defensive patterns
Strategy: try-catch
Validate before calling
data, _ := filelock.ReadFile(syPath)
if !json.Valid(data) {
return fmt.Errorf("corrupt document: %s", syPath)
} Try / catch
if err != nil && strings.HasPrefix(err.Error(), "invalid document JSON") {
// restore the file from history/snapshot before retrying
} Prevention
- Never hand-edit .sy files without JSON validation
- Ensure clean shutdown/backup to avoid truncated writes
- Validate .sy files after restore operations
When it happens
Trigger: A .sy file whose contents are truncated (interrupted write/pull), corrupted by an external editor or failed sync merge, binary garbage, or an empty file; encountered by FindAssetReferences/RelinkAsset during notebook traversal.
Common situations: Disk-full or power loss during a document save; git merge conflicts left conflict markers inside a .sy file; manual editing of .sy files with a text editor saving invalid JSON; a third-party tool writing partial JSON.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- decode existing session data failed
- invalid attribute view JSON
- parse encrypted notebook history conf
- parse parent document
- read attribute view custom color usage
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/9a07f9fcb0218dea.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/asset_relink.go:170
if !strings.HasSuffix(entry.Name(), ".sy") {
return nil
}
if err := p.observe(absPath); err != nil {
return err
}
p.reportProgress(absPath)
data, readErr := filelock.ReadFile(absPath)
if readErr != nil {
return readErr
}
if util.IsCiphertext(data) {
return fmt.Errorf("encrypted document in ordinary notebook: %s", absPath)
}
if readErr = treenode.CheckSpecJSON(data); readErr != nil {
return readErr
}
if !json.Valid(data) {
return fmt.Errorf("invalid document JSON: %s", absPath)
}
var header struct {
ID string `json:"ID"`
Properties struct {
Title string `json:"title"`
} `json:"Properties"`
}
if readErr = json.Unmarshal(data, &header); readErr != nil {
return readErr
}
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)View on GitHub (pinned to 9f775e8a12)