Reference
Limits and errors
Sandboxed execution
Every execution is metered. There is no unmetered mode. The JS host and the CLI both run every script under these limits.
| Limit | Value | What hitting it raises |
|---|---|---|
| Max call depth | 256 | RecursionError |
| Max operations | 100,000,000 | RuntimeError |
| Max memory | 256 MiB | MemoryError |
Memory and operations can be raised in three places.
- The
limitsoption ofcreateWorker, see JavaScript. - The
limitsof a group underedge actor, see Actors. - The
--memoryand--opsflags ofedge run,edge testandedge repl.
The call depth stays fixed. It sits below the depth where the wasm stack of either host runs out.
The memory limit counts what the program holds by one byte model, the same on every architecture.
| Held item | Bytes |
|---|---|
| Each object | 224 |
| Each value a list, tuple or attribute keeps | 8 |
| Each dict entry | 56 |
| Each set entry | 24 |
| Each string | Its length in bytes |
A number held in a container costs only its 8 bytes. Garbage is collected before the limit applies.
Only what the program still holds counts. A result too large for the limit, such as 'x' * 10**10, raises before it is built.
The op-limit RuntimeError cannot be caught. The except handler is entered, but its first operation raises again because the budget is still spent.
hit max depth
Integer width
Integers are two-tier.
- Inline (fast). 48-bit signed, packed into the NaN-boxed value. The range is
-140_737_488_355_328to140_737_488_355_327(-2^47to2^47 - 1). One ALU op per arithmetic, no allocation. - Wide (slow). 128-bit, heap-allocated. Used automatically when a literal exceeds the inline range or inline arithmetic overflows.
Promotion is automatic and invisible. Past ±2^127, arithmetic raises OverflowError.
Integers are not unbounded. Anything wider than 128 bits is out of scope by design.
140737488355327 140737488355328 1267650600228229401496703205376 overflow
pow(a, b, m) with a modulus is supported, but the modulus must stay below 2^63. A larger one raises ValueError, because the intermediate multiply would overflow 128 bits.
Source and token limits
These caps stop asymmetric inputs. Those are small sources that would produce huge parse trees or instruction streams. Each one is a compile-time diagnostic.
| Limit | Value | Diagnostic |
|---|---|---|
| Source size | 10 MiB | source file exceeds maximum size (10 MiB) |
| Indent depth | 100 | indentation depth exceeds maximum (100) |
| F-string nesting depth | 200 | f-string nesting depth exceeds maximum (200) |
| Expression nesting depth | 200 | expression too deeply nested |
| Instructions, names, or constants per chunk | 65,535 | program too large: exceeded the 65535 instruction, name, or constant limit |
| Call arguments | 255 positional, 255 keyword | too many arguments in call (max 255 positional and 255 keyword) |
| Native imports per module | 256 | too many native imports (max 256 per module) |
The lexer checks the source size before it scans anything. Compiler explains how the other caps stop the lexer and the parser.
repr output is truncated with a trailing , ... past 1,000,000 characters. Printing a huge structure cannot exhaust memory.
Compile-time errors
Syntax and resolution errors are reported as diagnostics with byte offsets into the source.
The CLI renders them with line, column, and a caret preview. They are caught before any code runs. try and except cannot catch them.
| Diagnostic | Cause |
|---|---|
expected X, got 'Y' | Unexpected token |
'(' was never closed (or '[' and '{') | Bracket opened with no matching closer |
')' does not match '[', expected ']' | Wrong closer kind for the innermost opener |
unexpected ')', no matching opener | Closer with no opener on the stack |
unterminated string literal | String missing its closing quote |
unterminated triple-quoted string literal | Triple-quoted string hit the end of the source |
unterminated f-string literal | F-string text hit the end of the source |
f-string was never closed | An interpolation hit the end of the source before the f-string closed |
inconsistent indentation: mixing tabs and spaces | Indent mixes both whitespace kinds |
unindent does not match any outer indentation level | Dedent lands between two outer levels |
integer literal too large to represent (max ±2^127) | Literal past the 128-bit cap |
'break' outside loop and 'continue' outside loop | Misplaced control keyword |
default 'except:' must be last | Bare except not at the end |
Generator expression must be parenthesized | A bare generator expression beside another argument or before a trailing comma |
'is' compares only with None, True, False, ... or NotImplemented | is against any other operand, compare it with == |
'id' is not supported, 'hash' is not supported, 'locals' is not supported | A use of a builtin the engine leaves out, unless the module binds the name |
'__del__' is not supported in a class body | A dunder the engine never calls, such as __hash__, __new__, __slots__, __init_subclass__ or a descriptor method |
class keywords such as 'metaclass' are not supported | A keyword in a class header |
a list, dict or set default is shared by every call | A mutable default, write None and build the value in the body |
named escapes are not supported | \N{...} in a string, write the character or \u03b1 |
complex numbers are not supported | A j suffix on a number |
The diagnostics of the source and token limits belong here too. Import failures are compile-time diagnostics as well, including modules Edge Python does not ship (os, sys, asyncio). See Modules for those message formats.
Runtime errors
Runtime errors raise as typed exceptions, catchable with try and except.
| Class | When |
|---|---|
TypeError | Wrong operand or argument type |
ValueError | Right type, invalid value |
AttributeError | Attribute not found on the object |
NameError | Undefined name |
UnboundLocalError | A local read or deleted before its first assignment |
ZeroDivisionError | Division or modulo by zero |
OverflowError | Integer arithmetic past ±2^127 |
KeyError | Dict or set lookup miss |
IndexError | Sequence index out of range |
StopIteration | Iterator exhausted |
AssertionError | Failed assert |
TimeoutError | with_timeout deadline expired |
CancelledError | Coroutine cancelled by cancel(). The cancelled coroutine cannot catch it |
SystemExit | raise SystemExit(code). Uncaught, the host exits with that code |
RecursionError | Past the call-depth limit |
MemoryError | Past the memory limit of the byte model |
RuntimeError | Past the op limit, an import cycle, input() without host data, or an internal invariant |
These errors fire from ordinary code.
TypeError: unsupported operand type(s) for +: 'int' and 'str' ValueError: int(): invalid literal KeyError: 'missing' IndexError: list index out of range NameError: name 'nope' is not defined ZeroDivisionError: division by zero AssertionError: math broke
SystemExit needs its own except clause. TimeoutError fires when a with_timeout deadline expires.
caught exit timed out
A user raise X raises whatever class or instance X is. Raising a value that does not derive from BaseException, such as a str or an int, raises TypeError with the message exceptions must derive from BaseException.
Exception hierarchy
except walks parent links in a curated tree rooted at BaseException.
| Class | Parent |
|---|---|
Exception, SystemExit, CancelledError | BaseException |
TypeError, ValueError, AttributeError, NameError, RuntimeError, LookupError, ArithmeticError, OSError, ImportError, StopIteration, StopAsyncIteration, AssertionError, MemoryError, TimeoutError | Exception |
IndexError, KeyError | LookupError |
OverflowError, ZeroDivisionError | ArithmeticError |
RecursionError, NotImplementedError | RuntimeError |
UnboundLocalError | NameError |
PermissionError | OSError |
UnicodeError | ValueError |
UnicodeEncodeError, UnicodeDecodeError | UnicodeError |
ModuleNotFoundError | ImportError |
IOError is another name for OSError. A system call raises PermissionError outside the grant of its package.
except Exception does not catch SystemExit or CancelledError. Catch them by name, through BaseException, or with a bare except. A cancelled coroutine cannot catch its own CancelledError at all, though its finally blocks still run.
caught via parent: oops caught IndexError as Exception
A class that derives from a built-in exception joins the tree. except ValueError catches a raised class Bad(ValueError), and except Bad catches its own subclasses.
- Its constructor arguments become
e.args. A call tosuper().__init__(...)sets them again. str(e)followse.argsunless the class defines__str__.- For
raise X from Yand chaining, see Control flow.
Bad 7 ('bad code', 7)Exception arguments
Caught exceptions expose their constructor arguments as e.args, a tuple.
raise X("msg")andraise X(a, b)carry their arguments through.- An error the runtime raises carries its message as a single argument.
- A bare
raise Xproduces an empty tuple.
('bad input',)
('division by zero',)
()Environmental errors
Some failures happen before the source reaches the compiler. They surface as plain text with no line or column, and script code cannot catch them.
| Error | When |
|---|---|
input rejected: invalid utf-8 at byte N | The source bytes from the host are not valid UTF-8 |
Check the encoding in the host before it hands the source to the compiler.
Determinism
The core language has no clock, randomness, threads, or OS access. The same source and the same input give the same output across runs and across x86_64, aarch64 and wasm32.
The system modules are the only way out, and each is held to a grant.
- Without any
timescope a run uses a virtual clock.sleepandwith_timeoutpass at once and in order, and a host call takes no time. - Any
timescope turns the wall clock on for the whole run. Timing then depends on when the program runs. fs,netandsecretreturn what the host holds at the moment of the call. Their results are as stable as those files, servers and values.