{"record":{"id":"f6630dd4a663d678","repo":"pydantic/monty","slug":"loadsession-loadsnapshot-is-only-valid-on-a-fresh-session","errorCode":null,"errorMessage":"loadSession / loadSnapshot is only valid on a fresh session, before any feedRun / feedStart / loadSession / loadSnapshot","messagePattern":"loadSession / loadSnapshot is only valid on a fresh session, before any feedRun / feedStart / loadSession / loadSnapshot","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/session.ts","lineNumber":340,"sourceCode":"      | NativeTurn\n      | LoadedTurn\n    if (turn.kind === 'loaded') {\n      throw await this.failedLoad(new Error('this dump is an idle session — use loadSession() to restore it'))\n    }\n    try {\n      return await driver.advance(turn)\n    } catch (err) {\n      // any failure restoring the snapshot (bad mount, crash, protocol desync)\n      // leaves the session unusable — poison it and release the worker\n      throw await this.failedLoad(err instanceof Error ? err : new Error(String(err)))\n    }\n  }\n\n  /** Claims a fresh session for a load (rejecting a reused one). */\n  private claimFresh(): void {\n    this.ensureUsable()\n    if (this.driven) {\n      throw new Error(\n        'loadSession / loadSnapshot is only valid on a fresh session, before any feedRun / feedStart / loadSession / loadSnapshot',\n      )\n    }\n    this.driven = true\n  }\n\n  /**\n   * Poisons the session and releases its worker after a failed load, so any\n   * later op fails like a crashed session — a failed load is not retryable.\n   * Returns the error to throw.\n   */\n  private async failedLoad(err: Error): Promise<Error> {\n    this.poison(err)\n    try {\n      await this.native.finish()\n    } catch {\n      // the worker was already discarded (e.g. it crashed) — nothing to release\n    }","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/session.ts#L322-L358","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst session = await pool.checkout()\nawait session.feedRun('x = 1')\nawait session.loadSnapshot(snapshot) // throws\n// after\nconst fresh = await pool.checkout()\nawait fresh.loadSnapshot(snapshot)","handlingStrategy":"validation","validationCode":"if (session.hasDriven /* track a flag: any feedRun/feedStart/load* returns true */) {\n  session = await pool.checkout()\n}\nawait session.loadSnapshot(snapshot)","typeGuard":"function isFreshSession(session: MontySession, driven: WeakSet<MontySession>): boolean {\n  return !driven.has(session)\n}","tryCatchPattern":"try {\n  await session.loadSession(data)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('only valid on a fresh session')) {\n    session = await pool.checkout()\n    await session.loadSession(data)\n  } else throw e\n}","preventionTips":["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"],"tags":["typescript","lifecycle","snapshots"],"backgroundTag":"invalid-state-transition","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}