stablyai/orca · warning · Error
terminal_history_recovery_protected
Error message
terminal_history_recovery_protected
What it means
terminal_history_recovery_protected: openSession detected a '.unreadable-recovery' marker file in the session's history directory. This marker is written when a previous generation was quarantined as unreadable, and its presence blocks a new writer from attaching to potentially corrupt data. Opening is refused unless quarantineUnreadableRecovery is explicitly requested to re-quarantine.
Source
Thrown at src/main/daemon/history-manager.ts:64
) {
this.onWriteError = opts?.onWriteError
this.checkpointMaxBytes = opts?.checkpointMaxBytes ?? TERMINAL_HISTORY_CHECKPOINT_MAX_BYTES
// Why: a quit between tombstone and reclaim leaves the tree on disk; nothing else rescans the queue.
schedulePendingSessionTreeRemovals(this.basePath)
}
async openSession(sessionId: string, opts: OpenSessionOptions): Promise<void> {
let recoveryFreeze = opts.recoveryFreeze
try {
this.disabledSessions.delete(sessionId)
const dir = join(this.basePath, getHistorySessionDirName(sessionId))
recoveryFreeze ??= await this.freezeForRecovery(sessionId)
const activeFreeze = this.requireRecoveryFreeze(sessionId, recoveryFreeze)
if (opts.quarantineUnreadableRecovery) {
quarantineTerminalHistorySession(this.basePath, sessionId, activeFreeze.fingerprint ?? null)
} else if (hasTerminalHistoryRecoveryProtection(this.basePath, sessionId)) {
throw new Error('terminal_history_recovery_protected')
} else if (
fingerprintTerminalHistorySession(this.basePath, sessionId) !== activeFreeze.fingerprint
) {
throw new Error('terminal_history_recovery_generation_changed')
}
this.recoveryFreezes.delete(sessionId)
mkdirSync(dir, { recursive: true })
const meta: SessionMeta = {
cwd: opts.cwd,
cols: opts.cols,
rows: opts.rows,
startedAt: new Date().toISOString(),
endedAt: null,
exitCode: null
}
writeFileSync(join(dir, 'meta.json'), JSON.stringify(meta, null, 2))
View on GitHub (pinned to 1136503c6a)
Solutions
- Pass quarantineUnreadableRecovery: true in OpenSessionOptions if you intend to re-quarantine and start clean.
- If the marker is stale and the directory is known-good, remove the .unreadable-recovery marker file manually (clearTerminalHistoryRecoveryProtection).
- Investigate why the marker was left behind (prior write failure / disk issue) before forcing removal.
- Treat history as best-effort: the session can still open without history rather than retrying indefinitely.
Example fix
// before: plain open on a protected dir
await history.openSession(id, { cwd, cols, rows })
// after: re-quarantine to start clean
await history.openSession(id, { cwd, cols, rows, quarantineUnreadableRecovery: true }) Defensive patterns
Strategy: fallback
Validate before calling
import { hasTerminalHistoryRecoveryProtection } from './terminal-history-recovery-quarantine'
if (hasTerminalHistoryRecoveryProtection(basePath, sessionId)) {
// decide: re-quarantine (quarantineUnreadableRecovery: true) or open without history
} Type guard
function isHistoryRecoveryProtected(e: unknown): boolean {
return e instanceof Error && e.message === 'terminal_history_recovery_protected'
} Try / catch
try {
await history.openSession(id, { cwd, cols, rows })
} catch (e) {
if (e instanceof Error && e.message === 'terminal_history_recovery_protected') {
// re-quarantine and start clean
await history.openSession(id, { cwd, cols, rows, quarantineUnreadableRecovery: true })
} else { throw e }
} Prevention
- Pass quarantineUnreadableRecovery when you intend to discard an unreadable generation.
- Investigate why the protection marker was left before removing it manually.
- Treat history as best-effort: let the session open without history if recovery is blocked.
When it happens
Trigger: openSession on a sessionId whose history dir contains the RECOVERY_PROTECTION_MARKER, with opts.quarantineUnreadableRecovery falsy. Typically a prior recovery attempt marked the directory unreadable and a new open is racing in without the quarantine flag.
Common situations: A crashed/corrupt history directory left the protection marker after a failed quarantine; restarting a session whose prior generation was unreadable; an external tool partially clearing the recovery-quarantine dir but leaving the marker.
Related errors
- terminal_history_recovery_generation_changed
- 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/b3353816edfe6438.
Report an issue: GitHub.