{"record":{"id":"158ad0520630287f","repo":"siyuan-note/siyuan","slug":"invalid-box-document-id-s","errorCode":null,"errorMessage":"invalid box document ID [%s]","messagePattern":"invalid box document ID \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box_doc.go","lineNumber":77,"sourceCode":"\nfunc readBoxDocID(boxID string) (ret string, err error) {\n\tdata, err := filelock.ReadFile(boxDocMetaPath(boxID))\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\terr = nil\n\t\t}\n\t\treturn\n\t}\n\n\tmeta := &boxDocMeta{}\n\tif err = gulu.JSON.UnmarshalJSON(data, meta); err != nil {\n\t\treturn \"\", fmt.Errorf(\"unmarshal box document metadata failed: %w\", err)\n\t}\n\tif boxDocMetaSpec != meta.Spec {\n\t\treturn \"\", fmt.Errorf(\"unsupported box document metadata spec [%d]\", meta.Spec)\n\t}\n\tif !ast.IsNodeIDPattern(meta.BoxDocID) {\n\t\treturn \"\", fmt.Errorf(\"invalid box document ID [%s]\", meta.BoxDocID)\n\t}\n\tif boxID != meta.BoxDocID {\n\t\treturn \"\", fmt.Errorf(\"box document ID [%s] does not match box ID [%s]\", meta.BoxDocID, boxID)\n\t}\n\treturn boxID, nil\n}\n\nfunc writeBoxDocID(boxID string) error {\n\tmeta := &boxDocMeta{Spec: boxDocMetaSpec, BoxDocID: boxID}\n\tdata, err := gulu.JSON.MarshalIndentJSON(meta, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal box document metadata failed: %w\", err)\n\t}\n\treturn filelock.WriteFile(boxDocMetaPath(boxID), data)\n}\n\nfunc IsBoxDocEnabled() bool {\n\treturn nil != Conf && nil != Conf.FileTree && nil != Conf.FileTree.BoxDocEnabled && *Conf.FileTree.BoxDocEnabled","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/box_doc.go#L59-L95","documentation":"Thrown by readBoxDocID in kernel/model/box_doc.go when parsing data/<boxID>/.siyuan/boxDoc.json, the metadata file that registers a notebook's hidden 'box document'. The boxDocID field fails ast.IsNodeIDPattern, i.e. it is not a valid SiYuan node ID (14-digit timestamp, dash, 7-char suffix, e.g. 20240102150405-a1b2c3d). The file is treated as untrusted on-disk state, so any malformed value aborts box-doc initialization for that notebook.","triggerScenarios":"Calling EnsureBoxDoc (notebook mount at kernel/model/mount.go:475, sync apply at kernel/model/repository.go:2509, or feature refresh) for a notebook whose boxDoc.json was hand-edited, truncated by a partial write, corrupted by an interrupted sync, or written by a different spec version. Empty or garbage boxDocID values reproduce it directly.","commonSituations":"Workspace restored from an incomplete backup; sync-conflict artifacts inside the notebook's .siyuan folder; external tools that rewrite/pretty-print the JSON and blank the field; manually copying a notebook folder and hand-editing only conf.json.","solutions":["Open <workspace>/data/<boxID>/.siyuan/boxDoc.json and inspect the boxDocID value; the filename <boxID> is the expected value","Set the file to {\"spec\":1,\"boxDocID\":\"<boxID>\"} where <boxID> is the notebook folder name, provided it matches the node-ID pattern","If the meta is unrecoverable, delete boxDoc.json (the kernel regenerates it on the next EnsureBoxDoc, reusing the existing hidden doc) and re-run the mount/open operation","Check kernel logs for 'initialized box document' to confirm recovery"],"exampleFix":"// before: data/20230102150405-a1b2c3d/.siyuan/boxDoc.json\n{\"spec\":1,\"boxDocID\":\"\"}\n// after\n{\"spec\":1,\"boxDocID\":\"20230102150405-a1b2c3d\"}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"boxDocID, err := model.EnsureBoxDoc(boxID)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid box document ID\") {\n\t\tlog.Printf(\"boxDoc.json for %s is malformed; regenerate it\", boxID)\n\t}\n\treturn err\n}","preventionTips":["Do not hand-edit boxDoc.json; let the kernel own it","Exclude data/*/.siyuan/ from external JSON formatters and linters","Validate workspace backups by mounting each notebook after restore","Keep regular kernel-version-consistent backups so metadata format stays native"],"tags":["siyuan","box-doc","notebook","metadata","validation"],"backgroundTag":"malformed-metadata-file","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}