stablyai/orca · warning · Error
terminal_history_recovery_generation_changed
Error message
terminal_history_recovery_generation_changed
What it means
terminal_history_recovery_generation_changed in quarantineTerminalHistorySession: the directory fingerprint re-computed at quarantine time does not match the expectedFingerprint passed in. The session dir changed between freeze and quarantine, so quarantining would move the wrong generation. The function throws before writing the protection marker or renaming, leaving the directory untouched.
Source
Thrown at src/main/daemon/terminal-history-recovery-quarantine.ts:80
const stats = lstatSync(name === '.' ? sessionDir : join(sessionDir, name))
fingerprint.update(name)
fingerprint.update('\0')
fingerprint.update(
[stats.dev, stats.ino, stats.mode, stats.size, stats.mtimeMs, stats.ctimeMs].join(':')
)
fingerprint.update('\0')
}
return fingerprint.digest('hex')
}
export function quarantineTerminalHistorySession(
basePath: string,
sessionId: string,
expectedFingerprint: TerminalHistoryDirectoryFingerprint
): string {
const actualFingerprint = fingerprintTerminalHistorySession(basePath, sessionId)
if (actualFingerprint !== expectedFingerprint) {
throw new Error('terminal_history_recovery_generation_changed')
}
const sessionDir = join(basePath, getHistorySessionDirName(sessionId))
const ownerDir = getTerminalHistoryQuarantineOwnerDir(basePath, sessionId)
// Why: if rename is blocked, a later adapter must not attach a writer to the unreadable generation.
writeFileSync(join(sessionDir, RECOVERY_PROTECTION_MARKER), '')
mkdirSync(ownerDir, { recursive: true })
const quarantineDir = join(ownerDir, randomUUID())
renameSync(sessionDir, quarantineDir)
return quarantineDir
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Re-capture the fingerprint immediately before calling quarantineTerminalHistorySession, or call it inside the same freeze that produced the expected fingerprint.
- Serialize recovery operations per session so no two quarantines/fingerprints race.
- Ensure no writer is active on the session dir during quarantine.
- If the change is expected, accept that the prior generation is gone and skip quarantine.
Defensive patterns
Strategy: fallback
Type guard
function isRecoveryGenerationChanged(e: unknown): boolean {
return e instanceof Error && e.message === 'terminal_history_recovery_generation_changed'
} Try / catch
try {
quarantineTerminalHistorySession(basePath, sessionId, expectedFingerprint)
} catch (e) {
if (e instanceof Error && e.message === 'terminal_history_recovery_generation_changed') {
// generation changed under us; skip quarantine and let history disable for this session
} else { throw e }
} Prevention
- Re-compute the fingerprint immediately before quarantine, inside the same freeze.
- Serialize recovery operations per session so no two races overlap.
- Ensure no writer is active on the dir during quarantine.
When it happens
Trigger: quarantineTerminalHistorySession(basePath, sessionId, expectedFingerprint) where fingerprintTerminalHistorySession now returns a different value than expectedFingerprint — the dir tree (entries, inodes, mtimes) was modified after the expected fingerprint was captured.
Common situations: A concurrent writer or another recovery pass modified the directory between fingerprint capture and quarantine; filesystem metadata churn from sync/AV; a race between two recovery attempts on the same session.
Related errors
- terminal_history_recovery_protected
- terminal_history_recovery_generation_changed
- Artifact create recovery record does not match its storage i
- Terminal history seed transfer digest mismatch
- Refusing to patch unexpected node-pty console-list agent sou
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/9625a562a555b9b3.
Report an issue: GitHub.