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

  1. Inspect the reported .sy file: repair or restore it from a snapshot/history backup or file history.
  2. If the document is unwanted, remove it from the notebook so the scan can proceed.
  3. Re-run relinking with dryRun=true after fixing to confirm the whole tree parses.
  4. Restore the workspace from sync or local history if multiple documents are corrupted.
  5. 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

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


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)