{"record":{"id":"4e39c23b7d9bacdd","repo":"siyuan-note/siyuan","slug":"mkdir-box-conf-dir-failed-w","errorCode":null,"errorMessage":"mkdir box conf dir failed: %w","messagePattern":"mkdir box conf dir failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box.go","lineNumber":325,"sourceCode":"\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\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}\n\nfunc (box *Box) Ls(p string) (ret []*FileInfo, totals int, err error) {\n\tif _, err = box.validateBoxPath(p); err != nil {\n\t\treturn\n\t}","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/box.go#L307-L343","documentation":"In saveConf0, os.MkdirAll(<DataDir>/<boxID>/.siyuan, 0755) is attempted; on failure it returns fmt.Errorf('mkdir box conf dir failed: %w', err). This creates the per-notebook .siyuan metadata directory before writing conf.json. It fails on permission denied, a read-only filesystem, ENOSPC, or when a non-directory file already exists at that path.","triggerScenarios":"Box.SaveConf on a notebook whose <DataDir>/<boxID> is not writable: SiYuan's data dir on a volume mounted read-only, permissions stripped, a regular file named '.siyuan' left there, or the disk is full.","commonSituations":"Running the kernel under a user without write access to the workspace; containerized deployment with an unmounted/broken volume; a previous crash left a '.siyuan' file instead of a directory; shared filesystem quota exhausted.","solutions":["Check write permissions and free space on the data volume (the workspace dir reported at boot).","If a file occupies <DataDir>/<boxID>/.siyuan, remove it so the directory can be created.","Run SiYuan under a user that owns (or can write) the workspace directory.","For read-only deployments, point --workspace at a writable location."],"exampleFix":"// before: assuming .siyuan always exists\nif err := box.saveConf0(data); err != nil { return err }\n\n// after: preflight the metadata dir and report a clearer error\ndir := filepath.Join(util.DataDir, box.ID, \".siyuan\")\nif info, e := os.Stat(dir); e == nil && !info.IsDir() {\n    return fmt.Errorf(\"%s exists but is not a directory; remove it and retry\", dir)\n}\nif err := box.saveConf0(data); err != nil { return err }","handlingStrategy":"validation","validationCode":"// Preflight the .siyuan metadata dir before saving.\ndir := filepath.Join(util.DataDir, box.ID, \".siyuan\")\nif info, err := os.Stat(dir); err == nil && !info.IsDir() {\n    return fmt.Errorf(\"%s is a file, not a directory\", dir)\n}","typeGuard":null,"tryCatchPattern":"// Report mkdir failures with the underlying OS error for fast diagnosis.\nif err := box.SaveConf(conf); err != nil {\n    if strings.Contains(err.Error(), \"mkdir box conf dir\") {\n        log.Errorw(\"mkdir failed\", \"box\", box.ID, \"root\", errors.Unwrap(err))\n    }\n}","preventionTips":["Run SiYuan under a user that owns the workspace directory.","Do not place a regular file at <boxID>/.siyuan.","Keep the data volume writable and not read-only."],"tags":["filesystem","notebook","config","permissions"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}