siyuan-note/siyuan · error
marshal notebook crypto backup failed: %w
Error message
marshal notebook crypto backup failed: %w
What it means
saveNotebookCryptoBackup marshals the NotebookCrypto configuration to JSON before the atomic write; this error wraps any json.Marshal failure. This is nearly impossible in practice because the struct contains only JSON-serializable fields, but if it happens (e.g. an unsupported field type introduced by code change or corruption) no backup is written.
Source
Thrown at kernel/model/crypto.go:404
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)
nc.KEKMAC = computeKEKMAC(nc, kek)
if !notebookCryptoConfigurationComplete(nc) {
return errors.New("cannot write incomplete notebook crypto backup")
}View on GitHub (pinned to 8641553a1f)
Solutions
- Check for modifications or forks of conf.NotebookCrypto that introduce unserializable fields
- Ensure no plugin/patch overrides MarshalJSON for NotebookCrypto
- Retry after restoring a stock kernel build; if reproducible, capture the wrapped inner error for a bug report
Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := json.Marshal(Conf.NotebookCrypto); err != nil {
// config struct not serializable; do not attempt backup save
}
Try / catch
if err := saveNotebookCryptoBackup(kek); err != nil {
if strings.Contains(err.Error(), "marshal notebook crypto backup failed") {
// inspect wrapped inner error; suspect struct/marshaler changes
}
}
Prevention
- Keep conf.NotebookCrypto limited to JSON-serializable fields
- Avoid custom MarshalJSON overrides on crypto config structs
- Test backup save paths after any struct change to conf.NotebookCrypto
When it happens
Trigger: json.Marshal(nc) returns an error inside saveNotebookCryptoBackup, called from EnableEncryptedNotebook, deriveKEK, or ChangeMasterPassword.
Common situations: A custom marshaler on conf.NotebookCrypto panicking or returning an error; an incompatible struct change (e.g. a func or channel field added) after a code upgrade; extremely rare in a released build.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- marshal AI editor actions failed: %w
- marshal box document metadata failed: %w
- marshal notebook crypt backup failed: %w
- marshal legacy AI editor actions failed: %w
- marshal box conf [%s] failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/f6817a8d749bbadf.
Report an issue: GitHub.