{"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":380,"sourceCode":"\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}\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":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/box.go#L362-L398","documentation":"saveConf0 creates the <DataDir>/<boxID>/.siyuan directory (0755) before writing conf.json. This error wraps os.MkdirAll failure — the OS refused to create the notebook config directory, typically due to filesystem permissions or the path being occupied by a non-directory file.","triggerScenarios":"Calling Box.SaveConf when os.MkdirAll(<DataDir>/<boxID>/.siyuan, 0755) fails: parent dir read-only, disk full, a file named .siyuan already exists, or insufficient OS permissions.","commonSituations":"Workspace on a read-only mount or external drive removed; running SiYuan as a user without write access to the data folder; sync client or backup tool replaced the .siyuan directory with a file; disk quota exceeded.","solutions":["Check OS permissions on <workspace>/data/<boxID>/ and ensure the process user can create directories there","Verify no file named .siyuan exists in the notebook folder — delete or rename it","Free disk space / raise quota if the disk is full","Remount the workspace volume read-write and retry the operation"],"exampleFix":"// shell check before retry\nls -la <workspace>/data/<boxID>/\nrm .siyuan  # if it is a regular file\nchmod u+w <workspace>/data/<boxID>","handlingStrategy":"try-catch","validationCode":"// Go: verify writability before the call\nif err := os.MkdirAll(filepath.Join(util.DataDir, box.ID, \".siyuan\"), 0755); err != nil {\n    return fmt.Errorf(\"data dir not writable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := box.SaveConf(conf); err != nil {\n    if strings.Contains(err.Error(), \"mkdir box conf dir failed\") {\n        // check permissions / disk space, then retry\n    }\n}","preventionTips":["Keep the workspace on a writable local volume","Never replace the .siyuan directory with a file","Run SiYuan as a user owning the data directory","Monitor disk space"],"tags":["go","filesystem","mkdir","permissions"],"backgroundTag":"mkdir-permission-denied","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"}