{"record":{"id":"0c5554c85c6cab08","repo":"siyuan-note/siyuan","slug":"parse-parent-document-s-w","errorCode":null,"errorMessage":"parse parent document [%s]: %w","messagePattern":"parse parent document \\[(.+?)\\]: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/filesys/tree.go","lineNumber":361,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdata, err = decryptDataWithDEK(boxID, filepath.ToSlash(relPath), data, dek)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif strict {\n\t\tif err = treenode.CheckSpecJSON(data); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tvar doc struct {\n\t\tID         string\n\t\tType       string\n\t\tProperties map[string]string\n\t}\n\tif err = json.Unmarshal(data, &doc); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse parent document [%s]: %w\", absPath, err)\n\t}\n\tif strict && (doc.ID != util.GetTreeID(absPath) || doc.Type != \"NodeDocument\") {\n\t\treturn nil, fmt.Errorf(\"invalid document identity [%s]\", absPath)\n\t}\n\tif len(doc.Properties) == 0 {\n\t\treturn nil, fmt.Errorf(\"missing parent document properties [%s]\", absPath)\n\t}\n\tfor key, value := range doc.Properties {\n\t\tdoc.Properties[key] = html.UnescapeAttrVal(value)\n\t}\n\treturn doc.Properties, nil\n}\n\nfunc DocIAL(absPath string) (ret map[string]string) {\n\t// 加密笔记本的 .sy 是密文，流式 jsoniter 解析无法处理，需先整体读+解密。\n\t// 反推 boxID：路径形如 <DataDir>/<boxID>/...；非加密笔记本走原流式逻辑。\n\tboxID := docIALBoxID(absPath)\n\tif boxID != \"\" && DEKProvider != nil {","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/filesys/tree.go#L343-L379","documentation":"readDocIAL extracts the document ID and properties from a .sy JSON file, optionally in strict mode. When json.Unmarshal fails on the file's bytes, the error is wrapped as \"parse parent document [%s]: %w\" so the caller knows which file failed and why. The wrapping distinguishes parse failures from a merely missing parent document.","triggerScenarios":"Reading a parent document whose JSON is truncated, corrupted (e.g. interrupted write or failed sync), not UTF-8, or has a top-level structure that cannot unmarshal into {ID, Type, Properties}.","commonSituations":"Partial .sy files after a crash or disk-full during write; merge/sync conflicts producing invalid JSON; manually edited documents with JSON syntax errors; byte-level corruption on disk.","solutions":["Open the .sy file at the reported path and fix or inspect its JSON validity.","Restore the corrupted document from sync snapshots, file history, or backup.","Re-index or rebuild the document if the corruption is unrecoverable from backups.","Check disk health/space if the file was truncated mid-write."],"exampleFix":"// no code fix — repair the data\n// before: data/<box>/20260101120000-abc.sy contains truncated JSON\n// after: restore a valid .sy from history/backup, then retry the operation","handlingStrategy":"try-catch","validationCode":"try { JSON.parse(require(\"fs\").readFileSync(syPath, \"utf8\")); } catch (e) { /* file is corrupt; restore before proceeding */ }","typeGuard":null,"tryCatchPattern":"ials, err := filesys.ReadDocHPath(absPath)\nif err != nil {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) { /* parent missing: safe to rebuild */ }\n    // otherwise parse/corruption error: restore from history or backup\n}","preventionTips":["Keep file history/sync snapshots enabled so corrupted .sy files are recoverable.","Avoid editing .sy files with external tools.","Monitor disk space; truncated JSON usually comes from interrupted writes."],"tags":["json","corruption","document-tree"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}