siyuan-note/siyuan · error
mkdir notebook crypt backup dir failed: %w
Error message
mkdir notebook crypt backup dir failed: %w
What it means
writeNotebookCryptBackup creates the directory that will hold the notebook's BoxCrypt backup file (via os.MkdirAll with 0755) and wraps any failure with this message. It is an I/O-level failure creating the backup directory, not a cryptographic problem.
Source
Thrown at kernel/model/crypto.go:2529
// 全局备份存 MasterSalt/KEKVerifier,per-notebook 备份存 WrappedDEK/WrapNonce。
const notebookCryptoBackupFilename = "notebook-crypto-backup.json"
func notebookCryptoBackupPath(boxID string) string {
return filepath.Join(util.DataDir, boxID, ".siyuan", notebookCryptoBackupFilename)
}
// writeNotebookCryptBackup 写入加密笔记本的 BoxCrypt 备份。
// 仅在 Encrypted=true 的笔记本上调用,配合 CreateEncryptedBox / ChangeMasterPassword 写入。
func writeNotebookCryptBackup(boxID string, crypt *conf.BoxEncryption) error {
if !ast.IsNodeIDPattern(boxID) {
return errors.New("invalid notebook ID")
}
if err := validateBoxEncryption(crypt); err != nil {
return err
}
backupPath := notebookCryptoBackupPath(boxID)
if err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {
return fmt.Errorf("mkdir notebook crypt backup dir failed: %w", err)
}
data, err := gulu.JSON.MarshalIndentJSON(crypt, "", " ")
if err != nil {
return fmt.Errorf("marshal notebook crypt backup failed: %w", err)
}
if err := filelock.WriteFile(backupPath, data); err != nil {
return fmt.Errorf("write notebook crypt backup failed: %w", err)
}
return nil
}
// readNotebookCryptBackup 读取加密笔记本的 BoxCrypt 备份。
// 备份文件不存在时返回 (nil, nil),调用方据此区分"非加密笔记本"和"备份不存在"。
func readNotebookCryptBackup(boxID string) (*conf.BoxEncryption, error) {
if !ast.IsNodeIDPattern(boxID) {
return nil, errors.New("invalid notebook ID")
}
backupPath := notebookCryptoBackupPath(boxID)View on GitHub (pinned to 8641553a1f)
Solutions
- Check the error wrapped by %w — fix the underlying cause (permissions, disk space, path conflict)
- Ensure the workspace data directory is writable by the SiYuan process user
- Remove or rename any regular file that occupies the backup directory path
- If running in Docker, mount the workspace volume read-write
Example fix
// before err := model.ChangeMasterPassword(box, old, new) // fails: mkdir ...: permission denied // after # fix host permissions first, e.g.: # chown -R 1000:1000 /siyuan/workspace err := model.ChangeMasterPassword(box, old, new)
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check writability
probe := filepath.Join(workspace, "data", ".write-test")
if err := os.WriteFile(probe, nil, 0644); err != nil {
return fmt.Errorf("workspace not writable: %w", err)
}
os.Remove(probe) Try / catch
if err := model.ChangeMasterPassword(box, old, new); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) { log.Printf("fs failure at %s: %v", perr.Path, perr.Err) }
return err
} Prevention
- Mount workspace volumes read-write and provision correct ownership
- Monitor disk free space before encryption operations
- Avoid pointing the workspace at network shares or sync-client-locked folders
When it happens
Trigger: os.MkdirAll(filepath.Dir(backupPath), 0755) fails during CreateEncryptedBox or ChangeMasterPassword — typically because the workspace data directory is read-only, disk is full, the path component exists as a regular file, or permission bits deny creation.
Common situations: SiYuan running with a read-only data directory (Docker volume mounted ro, sync client locking files); a stray file occupying the backup directory path; disk quota exhausted; running on Windows with the folder open/locked by another process.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- mkdir notebook crypto backup dir failed: %w
- create AI editor actions directory failed: %w
- mkdir box conf dir failed: %w
- create inline styles directory failed: %w
- create plugin dir [%s] failed: %s
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/37a6b30b9ede90e0.
Report an issue: GitHub.