Skip to main content

Overview

The ResourceLimits interface allows you to enforce limits on Python code execution to prevent resource exhaustion and ensure safe sandboxing of untrusted code. All limits are optional. Omit a field to disable that specific limit.

Interface

interface ResourceLimits {
  maxAllocations?: number
  maxDurationSecs?: number
  maxMemory?: number
  gcInterval?: number
  maxRecursionDepth?: number
}

Fields

maxAllocations
number
Maximum number of heap allocations allowed during execution.When this limit is reached, execution terminates with a ResourceError.Useful for preventing memory exhaustion from code that creates many objects.Example:
limits: { maxAllocations: 10000 }
maxDurationSecs
number
Maximum execution time in seconds (floating point).When this time limit is exceeded, execution terminates with a ResourceError.Useful for preventing infinite loops or long-running computations.Example:
limits: { maxDurationSecs: 5.0 }  // 5 seconds
limits: { maxDurationSecs: 0.1 }  // 100 milliseconds
maxMemory
number
Maximum heap memory in bytes.When heap memory usage exceeds this limit, execution terminates with a ResourceError.Useful for preventing memory exhaustion from large data structures.Example:
limits: { maxMemory: 1024 * 1024 }     // 1 MB
limits: { maxMemory: 10 * 1024 * 1024 } // 10 MB
gcInterval
number
Run garbage collection every N allocations.Controls how frequently the garbage collector runs. Lower values reduce peak memory usage but may slow execution. Higher values improve performance but may increase memory usage.If not specified, garbage collection is triggered automatically based on heap pressure.Example:
limits: { gcInterval: 1000 }  // GC every 1000 allocations
maxRecursionDepth
number
Maximum function call stack depth.Default: 1000When the call stack exceeds this depth, execution terminates with a RecursionError.Useful for preventing stack overflow from infinite recursion.Example:
limits: { maxRecursionDepth: 100 }  // Shallow stack
limits: { maxRecursionDepth: 5000 } // Deep stack

Usage Examples

Basic Resource Limiting

import { Monty } from '@pydantic/monty'

const m = new Monty('sum(range(1000000))')

try {
  const result = m.run({
    limits: {
      maxAllocations: 10000,
      maxDurationSecs: 1,
      maxMemory: 1024 * 1024, // 1MB
    },
  })
} catch (error) {
  if (error instanceof MontyRuntimeError) {
    console.log('Resource limit exceeded:', error.message)
  }
}

Preventing Infinite Recursion

const code = `
def infinite():
    return infinite()

infinite()
`

const m = new Monty(code)

try {
  m.run({
    limits: {
      maxRecursionDepth: 100,
    },
  })
} catch (error) {
  console.log('Caught recursion error')
}

Preventing Long-Running Code

const code = `
while True:
    pass
`

const m = new Monty(code)

try {
  m.run({
    limits: {
      maxDurationSecs: 0.1, // 100ms timeout
    },
  })
} catch (error) {
  console.log('Execution timed out')
}

Combining Multiple Limits

const m = new Monty('user_code', { inputs: ['user_code'] })

const result = m.run({
  inputs: { user_code: untrustedCode },
  limits: {
    maxAllocations: 50000,
    maxDurationSecs: 2,
    maxMemory: 5 * 1024 * 1024, // 5 MB
    maxRecursionDepth: 200,
    gcInterval: 5000,
  },
})

Using with runMontyAsync()

import { Monty, runMontyAsync } from '@pydantic/monty'

const m = new Monty('process_data(data)', { inputs: ['data'] })

const result = await runMontyAsync(m, {
  inputs: { data: largeDataset },
  limits: {
    maxMemory: 100 * 1024 * 1024, // 100 MB
    maxDurationSecs: 30,
  },
  externalFunctions: {
    process_data: async (data) => {
      return await expensiveProcessing(data)
    },
  },
})

Best Practices

Always set resource limits when executing untrusted code to prevent denial-of-service attacks and resource exhaustion.
When a resource limit is exceeded, execution terminates immediately. The heap may contain orphaned objects with incorrect reference counts. Always discard the Monty instance after a resource limit error.
const UNTRUSTED_CODE_LIMITS: ResourceLimits = {
  maxAllocations: 100000,
  maxDurationSecs: 5,
  maxMemory: 10 * 1024 * 1024, // 10 MB
  maxRecursionDepth: 500,
}

const m = new Monty(untrustedCode)
try {
  const result = m.run({ limits: UNTRUSTED_CODE_LIMITS })
} catch (error) {
  // Handle errors
}

See Also

Build docs developers (and LLMs) love