pydantic/monty · error · MontyRuntimeError

MemoryError

MemoryError

Error message

memory limit exceeded: ${used} bytes > ${maxBytes} bytes

What it means

A print-collector accumulated more bytes than its configured `maxBytes` cap, so `write` refuses the fragment and raises `MontyRuntimeError` with code `MemoryError`. This protects the host from unbounded output growth when collecting print output from sandboxed code.

Solutions

  1. Raise `maxBytes` when constructing the collector (or pass `null` to disable the cap)
  2. Reduce or batch the printed output in the sandboxed code
  3. Catch `MontyRuntimeError` in the print callback and stream fragments to disk/remote instead of accumulating in memory

Example fix

// before
const collector = new PrintCollector({ maxBytes: 1024 }) // too small for the run
// after
const collector = new PrintCollector({ maxBytes: 10 * 1024 * 1024 }) // 10 MiB, or null for no cap
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const text = await session.feedRun(code, { printCallback: collector.write.bind(collector) })
} catch (e) {
  if (e instanceof MontyRuntimeError && e.code === 'MemoryError' && e.message.startsWith('memory limit exceeded')) {
    // flush what was collected so far, raise cap, or stream to disk
  } else throw e
}

Prevention

When it happens

Trigger: Sandboxed code printing more total bytes than the collector's `maxBytes` (set in the constructor or per-feed print options); the throw happens inside `printCallback`/`write`, which typically aborts the running turn.

Common situations: Debug loops printing per-item in a large batch (10k lines), a worker emitting progress output in a loop, cap set for testing then code run against a large dataset.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


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

Appendix: source

Thrown at crates/monty-js/ts/print.ts:37

const utf8Encoder = new TextEncoder()

/** UTF-8 byte length of `text` (parity with Rust/Python `str`/`String` len). */
function utf8Len(text: string): number {
  return utf8Encoder.encode(text).byteLength
}

/**
 * Reject collect growth past `maxBytes`.
 * `null` = unlimited. Message must match ResourceError::Memory / check_print_collect_limit exactly.
 * Package-internal — do not re-export from index/node/wasm.
 */
function checkPrintCollectLimit(current: number, add: number, maxBytes: number | null): void {
  if (maxBytes === null) return
  // Caps stay far below Number.MAX_SAFE_INTEGER; plain + is exact for our sizes.
  const used = current + add
  if (used > maxBytes) {
    throw new MontyRuntimeError('MemoryError', `memory limit exceeded: ${used} bytes > ${maxBytes} bytes`)
  }
}

/**
 * Normalize constructor `maxBytes`: only `null` disables the cap.
 * Rejects NaN/Infinity (which would make `used > maxBytes` never true) and negatives.
 */
function resolveMaxBytes(maxBytes: number | null): number | null {
  if (maxBytes === null) return null
  if (typeof maxBytes !== 'number' || !Number.isFinite(maxBytes) || maxBytes < 0) {
    throw new TypeError('maxBytes must be a finite non-negative number or null')
  }
  return maxBytes
}

/**
 * Accumulates print fragments into one string. Pass as `printCallback`.
 * Default cap: DEFAULT_MAX_PRINT_COLLECT_BYTES. Pass maxBytes: null to disable.

View on GitHub (pinned to adc986b362)