siyuan-note/siyuan · error
read history snapshot [%s] failed: %w
Error message
read history snapshot [%s] failed: %w
What it means
When iterating a history snapshot directory (<ts>-<op> under data/history) to find per-box subdirectories, a failed os.ReadDir on that snapshot directory is wrapped as 'read history snapshot [%s] failed'. The library throws it because an unreadable snapshot prevents a complete scan, and callers (e.g. KEK verification, migration recovery) must not silently skip potentially encrypted history.
Source
Thrown at kernel/model/crypto.go:803
}
func encryptedNotebookHistoryBoxDirs() (ret []string, err error) {
entries, err := os.ReadDir(util.HistoryDir)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("read history dir failed: %w", err)
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
// 历史快照目录:<ts>-<op>,其下是各 boxID 子目录
snapshotDir := filepath.Join(util.HistoryDir, entry.Name())
boxEntries, readErr := os.ReadDir(snapshotDir)
if readErr != nil {
return nil, fmt.Errorf("read history snapshot [%s] failed: %w", entry.Name(), readErr)
}
for _, boxEntry := range boxEntries {
if !boxEntry.IsDir() || !ast.IsNodeIDPattern(boxEntry.Name()) {
continue
}
encrypted, checkErr := isEncryptedHistoryBoxDir(filepath.Join(snapshotDir, boxEntry.Name()))
if checkErr != nil {
return nil, checkErr
}
if encrypted {
ret = append(ret, filepath.Join(snapshotDir, boxEntry.Name()))
}
}
}
return ret, nil
}
func hasEncryptedNotebookDeleteHistory(boxID string) (bool, error) {View on GitHub (pinned to 8641553a1f)
Solutions
- Check the wrapped OS error for the snapshot named in [%s] and fix its permissions/availability
- Re-run the operation outside the history-retention window, or stop the pruning/cleanup job to avoid the delete race
- Restore the affected snapshot directory from backup if it is corrupt or a dangling symlink
- If the snapshot is disposable, move it out of data/history and re-run the scan; never delete recovery material of encrypted notebooks without confirming unencrypted history exists
Example fix
// before: prune while verifying
v.eachSnapshot(func(d string) { os.RemoveAll(d) })
go verifyKEKAgainstEncryptedHistory()
// after: verify first, prune after
verifyKEKAgainstEncryptedHistory()
thenPruneOldSnapshots() Defensive patterns
Strategy: retry
Validate before calling
for _, e := range mustRead(util.HistoryDir) { if !e.IsDir() { continue }; if _, err := os.ReadDir(filepath.Join(util.HistoryDir, e.Name())); err != nil { return err } } Try / catch
dirs, err := encryptedNotebookHistoryBoxDirs()
if err != nil {
if isTransient(err) { time.Sleep(retryDelay); retry() } // e.g. pruning race
return fmt.Errorf("history snapshot scan aborted, keeping recovery material: %w", err)
} Prevention
- Pause history retention/pruning while running KEK verification or migration
- Back up data/history before restore operations that move snapshot dirs
- Avoid partial (interrupted) snapshot copies between workspaces
- Re-run the scan once after fixing transient I/O errors before concluding data loss
When it happens
Trigger: scanEncryptedNotebookHistory or verifyKEKAgainstEncryptedHistory encountering a snapshot dir whose listing fails: permission denied on the snapshot dir, the snapshot entry is a symlink to an inaccessible target resolved differently per platform, or a race where the snapshot is deleted (history retention pruning) mid-scan so ReadDir gets ENOENT on the directory itself.
Common situations: History retention job concurrently deleting old snapshots while the KEK verification/migration scan runs; partial snapshot copy from backup or sync leaving broken entries; filesystem permission inconsistencies inside data/history/<ts>-<op>.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- read history dir failed: %w
- read encrypted notebook history conf [%s] failed: %w
- copy asset [%s] to [%s] failed: %w
- read session file failed: %w
- create session dir failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/9b7d0dae7e4d9ad2.
Report an issue: GitHub.