siyuan-note/siyuan · error
mkdir box conf dir failed: %w
Error message
mkdir box conf dir failed: %w
What it means
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.
Source
Thrown at kernel/model/box.go:325
return err
}
return syncBoxConfCryptoBackup(box.ID, persisted)
}
func syncBoxConfCryptoBackup(boxID string, boxConf *conf.BoxConf) error {
if !boxConf.Encrypted || boxConf.BoxCrypt == nil {
return nil
}
if needWriteNotebookCryptBackup(boxID, boxConf.BoxCrypt) {
return writeNotebookCryptBackup(boxID, boxConf.BoxCrypt)
}
return nil
}
func (box *Box) saveConf0(data []byte) error {
confPath := filepath.Join(util.DataDir, box.ID, ".siyuan/conf.json")
if err := os.MkdirAll(filepath.Join(util.DataDir, box.ID, ".siyuan"), 0755); err != nil {
return fmt.Errorf("mkdir box conf dir failed: %w", err)
}
if err := filelock.WriteFile(confPath, data); err != nil {
util.ReportFileSysFatalError(err)
return fmt.Errorf("write box conf [%s] failed: %w", confPath, err)
}
invalidateEncryptedPublishAccessCache()
return nil
}
// validateBoxPath 校验 box 内相对路径,拒绝 .. 和绝对路径,确保最终路径在 <DataDir>/<boxID>/ 内。
func (box *Box) validateBoxPath(p string) (string, error) {
return filesys.ValidateBoxRelativePath(box.ID, p)
}
func (box *Box) Ls(p string) (ret []*FileInfo, totals int, err error) {
if _, err = box.validateBoxPath(p); err != nil {
return
}View on GitHub (pinned to 251596fc0d)
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.
Example fix
// before: assuming .siyuan always exists
if err := box.saveConf0(data); err != nil { return err }
// after: preflight the metadata dir and report a clearer error
dir := filepath.Join(util.DataDir, box.ID, ".siyuan")
if info, e := os.Stat(dir); e == nil && !info.IsDir() {
return fmt.Errorf("%s exists but is not a directory; remove it and retry", dir)
}
if err := box.saveConf0(data); err != nil { return err } Defensive patterns
Strategy: validation
Validate before calling
// Preflight the .siyuan metadata dir before saving.
dir := filepath.Join(util.DataDir, box.ID, ".siyuan")
if info, err := os.Stat(dir); err == nil && !info.IsDir() {
return fmt.Errorf("%s is a file, not a directory", dir)
} Try / catch
// Report mkdir failures with the underlying OS error for fast diagnosis.
if err := box.SaveConf(conf); err != nil {
if strings.Contains(err.Error(), "mkdir box conf dir") {
log.Errorw("mkdir failed", "box", box.ID, "root", errors.Unwrap(err))
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- write box conf [%s] failed: %w
- prepare box conf [%s] failed: %w
- create dir for publishAccess.json [%s] failed: %s
- resolve assets directory [%s] failed: %w
- resolve asset [%s] failed: %w
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/4e39c23b7d9bacdd.
Report an issue: GitHub.