siyuan-note/siyuan · error

notebook crypto backup is incomplete or corrupted

Error message

notebook crypto backup is incomplete or corrupted

What it means

The backup file passed the spec check but notebookCryptoConfigurationComplete reports that required crypto fields are missing. The library treats this as a corrupted or tampered backup and refuses to use it for key derivation or restore, protecting against silently restoring broken encryption state.

Source

Thrown at kernel/model/crypto.go:497

// loadNotebookCryptoBackup 从 DataDir 读取 NotebookCrypto 备份。文件不存在返回 (nil, nil)。
func loadNotebookCryptoBackup() (*conf.NotebookCrypto, error) {
	data, err := filelock.ReadFile(dataCryptoBackupPath())
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	nc := &conf.NotebookCrypto{}
	if err := json.Unmarshal(data, nc); err != nil {
		return nil, err
	}
	if nc.Spec != conf.CurrentNotebookCryptoSpec {
		return nil, fmt.Errorf("unsupported notebook crypto backup spec [%d]", nc.Spec)
	}
	if !notebookCryptoConfigurationComplete(nc) {
		return nil, errors.New("notebook crypto backup is incomplete or corrupted")
	}
	return nc, nil
}

// removeNotebookCryptoBackup 删除备份文件(禁用加密功能时调用)。文件不存在视为成功。
func removeNotebookCryptoBackup() {
	if err := os.Remove(dataCryptoBackupPath()); err != nil && !os.IsNotExist(err) {
		logging.LogErrorf("remove notebook crypto backup failed: %s", err)
	}
}

// masterPasswordMigration 记录改密迁移的完整状态,用于崩溃后恢复。
type masterPasswordMigration struct {
	OldVerifier      []byte              `json:"oldVerifier"`
	NewVerifier      []byte              `json:"newVerifier"`
	NewVerifierNonce []byte              `json:"newVerifierNonce"`
	NewKDFParams     json.RawMessage     `json:"newKDFParams"`
	NewHistoryKEKs   [][]byte            `json:"newHistoryKEKs,omitempty"`

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Restore the backup file from a verified copy (file-level restore or another machine's backup)
  2. Delete the corrupt backup and re-run the master password / KEK setup to generate a fresh complete backup
  3. Verify the backup file parses to a fully populated NotebookCrypto struct before relying on it
  4. If recovery is impossible, use the documented master password recovery flow rather than forcing the corrupt backup

Example fix

// before: trusting a truncated backup
nc, err := loadNotebookCryptoBackup() // incomplete
// after: keep verified copies
if err := verifyBackupIntegrity(backupPath); err != nil {
    restoreFromVerifiedCopy(backupPath)
}
nc, err := loadNotebookCryptoBackup()
Defensive patterns

Strategy: fallback

Validate before calling

var nc conf.NotebookCrypto
if err := json.Unmarshal(raw, &nc); err != nil {
    return fmt.Errorf("corrupt backup: %w", err)
}
if !notebookCryptoConfigurationComplete(&nc) {
    return fmt.Errorf("backup incomplete: refuse to use")
}

Try / catch

nc, err := loadNotebookCryptoBackup()
if err != nil {
    // fall back to the documented recovery flow; never force the corrupt backup
    if restoreErr := restoreBackupFromVerifiedCopy(); restoreErr != nil {
        return fmt.Errorf("no valid backup available: %w", restoreErr)
    }
    nc, err = loadNotebookCryptoBackup()
}

Prevention

When it happens

Trigger: loadNotebookCryptoBackup reads a backup whose Spec matches but is missing mandatory fields (empty WrappedDEK, salt, KEKMAC, etc.) — via restoreNotebookCryptoConfigFromBackup, deriveNotebookCryptoBackupCandidate, or deriveKEK.

Common situations: Truncated backup file after a crash, manual edits removing fields, a backup written by a buggy older build, or file corruption on disk.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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