siyuan-note/siyuan · error

mkdir notebook crypto backup dir failed: %w

Error message

mkdir notebook crypto backup dir failed: %w

What it means

saveNotebookCryptoBackup creates the parent directory of the crypto backup file with os.MkdirAll before writing it; if that fails the error is wrapped with this message. This means the workspace data directory could not be created or is inaccessible, so no backup file can be persisted. The in-memory Conf.NotebookCrypto fields are already updated at this point, but the on-disk backup is missing.

Source

Thrown at kernel/model/crypto.go:400

		return errors.New("cannot generate notebook crypto backup without KEK")
	}
	Conf.m.Lock()
	nc := *Conf.NotebookCrypto // 值拷贝
	prepareBackupForWrite(&nc)
	nc.KEKMAC = computeKEKMAC(&nc, kek)
	if !notebookCryptoConfigurationComplete(&nc) {
		Conf.m.Unlock()
		return errors.New("cannot save incomplete notebook crypto configuration")
	}
	Conf.NotebookCrypto.Spec = nc.Spec
	Conf.NotebookCrypto.BackupID = nc.BackupID
	Conf.NotebookCrypto.CreatedAt = nc.CreatedAt
	Conf.NotebookCrypto.Checksum = nc.Checksum
	Conf.NotebookCrypto.KEKMAC = nc.KEKMAC // 保持 Conf 与备份文件的 KEKMAC 一致
	Conf.m.Unlock()
	backupPath := dataCryptoBackupPath()
	if err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {
		return fmt.Errorf("mkdir notebook crypto backup dir failed: %w", err)
	}
	data, err := json.Marshal(nc)
	if err != nil {
		return fmt.Errorf("marshal notebook crypto backup failed: %w", err)
	}
	if err := atomicWriteFile(backupPath, data); err != nil {
		return fmt.Errorf("write notebook crypto backup failed: %w", err)
	}
	return nil
}

// writeNotebookCryptoBackupData 将指定的 NotebookCrypto 写入备份文件(不依赖 Conf.NotebookCrypto)。
// kek 必须非 nil:在 Checksum 定型后计算 KEKMAC,保证落盘 MAC 与落盘内容一致。
func writeNotebookCryptoBackupData(nc *conf.NotebookCrypto, kek []byte) error {
	if kek == nil {
		return errors.New("cannot generate notebook crypto backup without KEK")
	}
	prepareBackupForWrite(nc)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check and fix filesystem permissions on the workspace data directory so the kernel process can create subdirectories (mkdir/take ownership as needed)
  2. Free disk space if the volume is full, or move the workspace to a writable volume
  3. Check OS-level restrictions (SELinux denials, antivirus, sandbox profiles) that block writes inside the data path

Example fix

// before: enabling encryption on a read-only workspace
EnableEncryptedNotebook(...)
// after: verify writability first
if err := checkWritableDir(util.DataDir); err != nil {
    return fmt.Errorf("data dir not writable: %w", err)
}
err := EnableEncryptedNotebook(...)
Defensive patterns

Strategy: try-catch

Validate before calling

if info, err := os.Stat(util.DataDir); err != nil || !info.IsDir() {
    // workspace data dir missing or inaccessible
}

Try / catch

if err := EnableEncryptedNotebook(...); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {
        // fix permissions on data dir, then retry
    }
}

Prevention

When it happens

Trigger: os.MkdirAll(filepath.Dir(dataCryptoBackupPath()), 0755) returns an error during EnableEncryptedNotebook, deriveKEK, or ChangeMasterPassword — e.g. the data directory is read-only, owned by another user, on a full/removable disk, or blocked by sandboxing/antivirus.

Common situations: Running SiYuan from a read-only mount or portable disk; workspace moved to a path the process user cannot write; disk full; SELinux/AppArmor or Windows folder permissions blocking directory creation under the data directory.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/269a91560fd0a463. Report an issue: GitHub.