{"record":{"id":"52ad5ee8ee84137a","repo":"siyuan-note/siyuan","slug":"invalid-box-id-s-52ad5e","errorCode":null,"errorMessage":"invalid box ID [%s]","messagePattern":"invalid box ID \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box.go","lineNumber":375,"sourceCode":"\tif err = box.saveConf0(newData); err != nil {\n\t\treturn err\n\t}\n\treturn syncBoxConfCryptoBackup(box.ID, persisted)\n}\n\nfunc syncBoxConfCryptoBackup(boxID string, boxConf *conf.BoxConf) error {\n\tif !boxConf.Encrypted || boxConf.BoxCrypt == nil {\n\t\treturn nil\n\t}\n\tif needWriteNotebookCryptBackup(boxID, boxConf.BoxCrypt) {\n\t\treturn writeNotebookCryptBackup(boxID, boxConf.BoxCrypt)\n\t}\n\treturn nil\n}\n\nfunc (box *Box) saveConf0(data []byte) error {\n\tif !ast.IsNodeIDPattern(box.ID) {\n\t\treturn fmt.Errorf(\"invalid box ID [%s]\", box.ID)\n\t}\n\n\tconfPath := filepath.Join(util.DataDir, box.ID, \".siyuan/conf.json\")\n\tif err := os.MkdirAll(filepath.Join(util.DataDir, box.ID, \".siyuan\"), 0755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir box conf dir failed: %w\", err)\n\t}\n\tif err := filelock.WriteFile(confPath, data); err != nil {\n\t\tutil.ReportFileSysFatalError(err)\n\t\treturn fmt.Errorf(\"write box conf [%s] failed: %w\", confPath, err)\n\t}\n\tinvalidateEncryptedPublishAccessCache()\n\treturn nil\n}\n\n// validateBoxPath 校验 box 内相对路径，拒绝 .. 和绝对路径，确保最终路径在 <DataDir>/<boxID>/ 内。\nfunc (box *Box) validateBoxPath(p string) (string, error) {\n\treturn filesys.ValidateBoxRelativePath(box.ID, p)\n}","sourceCodeStart":357,"sourceCodeEnd":393,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/box.go#L357-L393","documentation":"saveConf0 validates that the box ID is a syntactically valid SiYuan node ID (ast.IsNodeIDPattern, a 14-char lowercase alnum string) before writing conf.json. This error means the Box struct carries an ID that is not a valid notebook identifier, so the write is refused to avoid creating garbage directories under DataDir.","triggerScenarios":"Calling Box.SaveConf on a Box whose ID was constructed programmatically (not loaded from disk), e.g. an empty ID, a path fragment, or an ID with invalid characters. Raised by saveConf0 which is invoked from SaveConf whenever conf.json must be written.","commonSituations":"Tests constructing Box{ID: \"test\"} directly; plugins or scripts passing fabricated notebook IDs; corrupted in-memory state after a failed box load; migrating data with legacy/renamed notebook folder names.","solutions":["Ensure the Box was created via a valid notebook creation path so the ID matches the node-ID pattern (14 lowercase alphanumerics)","Check the directory name under the workspace data/ folder — it must be a valid node ID","If constructing a Box in tests, use a generated valid ID (e.g. via the ID generator) instead of a literal","Guard callers: verify ast.IsNodeIDPattern(box.ID) before calling SaveConf"],"exampleFix":"// before\nbox := &Box{ID: \"my-notebook\"}\nerr := box.SaveConf(conf)\n// after\nif !ast.IsNodeIDPattern(box.ID) {\n    return fmt.Errorf(\"refusing to save conf: invalid box ID %q\", box.ID)\n}\nerr := box.SaveConf(conf)","handlingStrategy":"validation","validationCode":"// Go: validate the box ID before saving\nif !ast.IsNodeIDPattern(box.ID) {\n    return fmt.Errorf(\"invalid notebook ID %q\", box.ID)\n}","typeGuard":null,"tryCatchPattern":"if err := box.SaveConf(conf); err != nil {\n    if strings.Contains(err.Error(), \"invalid box ID\") {\n        // recreate Box from a valid notebook path\n    }\n}","preventionTips":["Never construct Box structs with hand-made IDs","Load boxes via the standard listing/loading API","In tests, generate IDs with the node-ID generator"],"tags":["go","validation","notebook","identifier"],"backgroundTag":"invalid-identifier-format","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"}