pydantic/monty · error · Error

resumeNotHandled is only valid for OS-call snapshots

Error message

resumeNotHandled is only valid for OS-call snapshots

What it means

`resumeNotHandled` tells monty to apply its default unhandled behaviour for an OS-call suspension. It is only meaningful when the snapshot paused on an OS function call; the method checks `isOsFunction` and throws this Error otherwise. This guards the protocol: every resume variant only accepts the suspension kind it was designed for.

Source

Thrown at crates/monty-js/ts/session.ts:1002

  }

  /** Resumes as "no such function": the sandbox raises `NameError`. */
  resumeNotFound(): Promise<Snapshot> {
    this.claim()
    return this.driver.resumeNotFound()
  }

  /** Registers the call as a pending future; other sandbox tasks keep
   *  running and surface later as a [`FutureSnapshot`]. */
  resumeFuture(): Promise<Snapshot> {
    this.claim()
    return this.driver.resumeFuture()
  }

  /** Resumes an OS call with monty's default unhandled behaviour. */
  resumeNotHandled(): Promise<Snapshot> {
    if (!this.isOsFunction) {
      throw new Error('resumeNotHandled is only valid for OS-call snapshots')
    }
    this.claim()
    return this.driver.resumeNotHandled()
  }

  /** Serializes the paused worker; restore with `session.loadSnapshot`. */
  dump(): Promise<Buffer> {
    return this.driver.dump()
  }
}

/** A paused execution waiting for the value of an undefined name. */
export class NameLookupSnapshot extends SingleUse {
  readonly variableName: string
  /** Set for lazy attribute lookups on a host-backed object (a class
   *  instance, or a class type): the receiver's store uuid. `null` for
   *  plain name lookups. */
  readonly objectId: string | null

View on GitHub (pinned to adc986b362)

Solutions

  1. Only call resumeNotHandled on snapshots representing OS calls; dispatch on the snapshot/turn kind first.
  2. For external-function suspensions use resumeReturn/resumeError/resumeNotFound; for futures use resumeFuture.
  3. In a generic driver, check the snapshot type (e.g. `instanceof OsFunctionSnapshot` or an `isOsFunction` flag) before choosing the resume method.

Example fix

// before
async function resumeAny(snap: Snapshot) {
  return snap.resumeNotHandled()
}

// after
async function resumeAny(snap: Snapshot) {
  if (snap.isOsFunction) return snap.resumeNotHandled()
  return snap.resumeNotFound()
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Check snapshot kind before resuming:
// if ('isOsFunction' in snap && snap.isOsFunction) { ... }
const isOsSnapshot = typeof (snap as { isOsFunction?: boolean }).isOsFunction === 'boolean'
  ? (snap as { isOsFunction: boolean }).isOsFunction
  : false

Type guard

function isOsCallSnapshot(snap: Snapshot): snap is Snapshot & { isOsFunction: true } {
  return (snap as { isOsFunction?: boolean }).isOsFunction === true
}

Try / catch

try {
  await snap.resumeNotHandled()
} catch (err) {
  if (err instanceof Error && err.message.includes('resumeNotHandled is only valid')) {
    await snap.resumeNotFound() // or dispatch per kind
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: Calling `snapshot.resumeNotHandled()` when the snapshot was paused on an external-function call (`# call-external`) or a future rather than an `os`/OsFunctionCall suspension.

Common situations: A generic drive loop that handles all suspensions with one code path and unconditionally calls resumeNotHandled; confusion between external-function snapshots (resumeReturn/resumeError/resumeNotFound) and OS-call snapshots.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/84a2c158b12a06c8. Report an issue: GitHub.