When a function invocation fails, the engine returns an ErrorBody with three fields. The code is the stable identifier you should match on; the message is human-readable and may evolve.
Field
Type
Description
code
string
Stable error code (e.g. invocation_stopped, function_not_found). The wire ABI — match on this for targeted recovery.
message
string
Human-readable explanation. Often includes the offending function ID, payload size, or limit value.
stacktrace
string | null
Optional worker-side stacktrace, when the failure originated in handler code.
SDKs surface these as language-native exceptions:
Node — Error with the engine code / message / stacktrace propagated through.
Python — IIIRemoteError carrying the code and message.
An in-flight invocation was halted by a clean worker disconnect, engine shutdown, or EOF on the WebSocket. The legacy generic stop code.
Usually transient. Retry idempotent calls; if the worker is gone for good, re-route or fail the upstream caller.
invocation_failed_payload_too_large
The engine closed the WebSocket because an inbound message from the worker exceeded iii-worker-manager.max_message_size (default 16 MiB). Any in-flight invocation on that connection resolves with this code.
Shrink the payload, raise max_message_size on both the engine config and the SDK InitOptions, or move binary data to channels.
function_not_found
A trigger() referenced a function ID that is not registered with the engine.
Check the function ID for typos; verify the worker that owns it is connected.
invocation_error
The engine could not deliver the invocation to the target worker (channel send failed, worker dropped mid-route).
Retry; if persistent, inspect engine logs for the underlying transport error.
serialization_error
The engine failed to serialize or deserialize an invocation payload, response, or error envelope.
The payload contains a value that does not round-trip through JSON. Inspect the offending field.
registration_failed
A worker’s register_function / register_trigger message was rejected (duplicate ID, malformed format, or invalid trigger config).
Check the registration message against the SDK reference and the engine logs for the rejection reason.
timeout
The engine’s per-invocation deadline expired before the worker returned a result.
Raise invocation_timeout_ms on InitOptions or timeout_ms on the trigger request, or split the work.
Some failures never reach the engine. SDKs include a producer-side guard that runs before the WebSocket send, so oversized payloads fail fast with a local exception instead of triggering a server-side disconnect:
SDK
Exception
Trigger
Python
IIIPayloadTooLarge (subclass of ValueError) carrying payload_bytes / limit_bytes.
Serialized message would exceed InitOptions.max_message_size.
Serialized message would exceed InitOptions::resolved_max_message_size().
The message wording is identical across all three SDKs:
Payload {n} bytes exceeds invocation limit {limit} bytes. For binary blobs use channels: https://iii.dev/docs/how-to/use-channels
If you raise the SDK limit above the engine’s max_message_size, you skip the local guard but then trip invocation_failed_payload_too_large on the server side. Keep the two values aligned.