pydantic/monty · error · Error
loadSession / loadSnapshot is only valid on a fresh session,
Error message
loadSession / loadSnapshot is only valid on a fresh session, before any feedRun / feedStart / loadSession / loadSnapshot
What it means
Snapshot restore (`loadSession`/`loadSnapshot`) is only valid on a brand-new session before any driving call. Once a session has run `feedRun`/`feedStart` or already loaded a snapshot, its worker state is no longer pristine, so restoring would corrupt it; an `Error` is thrown.
Source
Thrown at crates/monty-js/ts/session.ts:340
| NativeTurn
| LoadedTurn
if (turn.kind === 'loaded') {
throw await this.failedLoad(new Error('this dump is an idle session — use loadSession() to restore it'))
}
try {
return await driver.advance(turn)
} catch (err) {
// any failure restoring the snapshot (bad mount, crash, protocol desync)
// leaves the session unusable — poison it and release the worker
throw await this.failedLoad(err instanceof Error ? err : new Error(String(err)))
}
}
/** Claims a fresh session for a load (rejecting a reused one). */
private claimFresh(): void {
this.ensureUsable()
if (this.driven) {
throw new Error(
'loadSession / loadSnapshot is only valid on a fresh session, before any feedRun / feedStart / loadSession / loadSnapshot',
)
}
this.driven = true
}
/**
* Poisons the session and releases its worker after a failed load, so any
* later op fails like a crashed session — a failed load is not retryable.
* Returns the error to throw.
*/
private async failedLoad(err: Error): Promise<Error> {
this.poison(err)
try {
await this.native.finish()
} catch {
// the worker was already discarded (e.g. it crashed) — nothing to release
}View on GitHub (pinned to adc986b362)
Solutions
- Check out a fresh session (`pool.checkout()`) for each `loadSession`/`loadSnapshot` call
- Load the snapshot as the very first operation on the session
- If resuming after failure, close the old session and check out a new one before loading
Example fix
// before
const session = await pool.checkout()
await session.feedRun('x = 1')
await session.loadSnapshot(snapshot) // throws
// after
const fresh = await pool.checkout()
await fresh.loadSnapshot(snapshot) Defensive patterns
Strategy: validation
Validate before calling
if (session.hasDriven /* track a flag: any feedRun/feedStart/load* returns true */) {
session = await pool.checkout()
}
await session.loadSnapshot(snapshot) Type guard
function isFreshSession(session: MontySession, driven: WeakSet<MontySession>): boolean {
return !driven.has(session)
} Try / catch
try {
await session.loadSession(data)
} catch (e) {
if (e instanceof Error && e.message.includes('only valid on a fresh session')) {
session = await pool.checkout()
await session.loadSession(data)
} else throw e
} Prevention
- Treat loadSession/loadSnapshot as session constructors: always on a brand-new checkout
- Track a `driven` flag per session in wrappers around the API
- Never reload a snapshot as a retry mechanism on the same session
When it happens
Trigger: Calling `session.loadSession(...)` after a prior `feedRun`/`feedStart`, or calling `loadSnapshot` twice on the same session; also reusing a pooled session returned from a previous checkout's logical flow.
Common situations: Replaying snapshots in a loop reusing one session object, resuming a saved session into a session that already ran warm-up code, retry logic that reloads a snapshot after a failed turn.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- the pool is closed — create a new Monty pool
- the session is closed — check out a new one
- ClassInstance expects an object instance
- notCallableMessage(method)
- ClassInstance expects an instance of a class, not a null-pro
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/f6630dd4a663d678.
Report an issue: GitHub.