Error codes

type CodeModeErrorCode =
  | "invalid_input"
  | "runtime_unavailable"
  | "aborted"
  | "timeout"
  | "output_limit_exceeded"
  | "snapshot_limit_exceeded"
  | "internal_error";

invalid_input covers bad exec/wait arguments, including retired language and typecheck fields, rejected module access, JavaScript syntax errors, unknown/expired/ wrong-scope runId values, and too many suspended runs. It also covers an uncaught nested tool call that the host rejected as invalid input (an input_contract schema mismatch or a tool's own input error); the error names the missing or unexpected arguments. Other uncaught tool failures report internal_error. Codes the guest assigns to error.code never change the terminal code. runtime_unavailable covers an unavailable executor or a worker that fails to start or exits unexpectedly. Check the selected tools.codeMode.executor and its plugin availability; the quickjs executor requires the bundled code-mode-quickjs runtime. Explicit selection activates that bundle despite generic plugin disable or allowlist settings, but an explicit deny or disabled entry still blocks it. Apus does not switch executors automatically. aborted means the caller cancelled an active exec or wait; Apus terminates the worker or drops the suspended run, so that runId cannot be resumed. It is distinct from timeout, which means an execution deadline was exceeded. output_limit_exceeded is reserved for a result that cannot be serialized into the bounded projection; ordinary oversized successful results are truncated and remain successful.

JavaScript syntax errors are rejected during source preparation, before any nested tool dispatch. The bounded diagnostic includes a one-based source line and column. Malformed JavaScript reports its syntax error before module-access checks. Correct the source and submit a new exec; Apus does not repair or replay it automatically. This no-dispatch outcome does not enable restartSafe or change the result's replaySafe flag. Exceptions thrown by valid guest code, including SyntaxError, remain runtime failures.

The current parser has a known limitation with division immediately after an optional keyword-named property, such as value?.return / 2 / 3. This is valid JavaScript, but source preparation rejects it before tool dispatch. Parenthesize the property access: (value?.return) / 2 / 3.

Errors returned to the guest are plain data; host Error instances, stack objects and prototypes are not passed through the JSON result bridge. This bridge contract does not make the Node executor a security boundary; see Code Mode executors.

failurePhase identifies where the terminal error originated. An uncaught rejected tool call reports "bridge"; a new JavaScript error after a successful call or a caught tool rejection reports "guest". Rethrowing the original tool error keeps "bridge", including after wait. Bridge failure origin and code come only from host replies. Guest code cannot settle its own pending tool calls or forge bridge provenance.

Failure origin is separate from replay safety. When bridgeDispatchStarted is true and replaySafe is false, check the destination before repeating a send or another action that changes state—even for a guest error. A failed exec does not by itself prove that a message was not delivered.

Telemetry

Each result's telemetry field reports: hidden catalog size and a source breakdown (apus/mcp/client counts), cumulative search/describe/call counts for the run's catalog, and the code-mode control tool names (exec and wait). The counterScope identifies one counter lifetime, changing when a catalog is replaced or restored but remaining stable when tools are appended or prompt policy narrows that catalog.

Catalog teardown retains only these final aggregate diagnostics, not executable tools or VM state. If teardown closes a suspended run while wait is observing pending work, that wait returns failed with code: "aborted" and the final telemetry; pending calls are canceled and the continuation is released. Retained diagnostics grant no authority to resume or repair the closed run.

The run metadata (meta.agentMeta in apus agent --json, mirrored on the agent exec --json envelope) adds per-run stats:

Telemetry must not include secrets, raw environment values, or unredacted tool inputs beyond existing Apus trajectory policy.

Debugging

JavaScript failure frames labeled apus-code-mode:user.js use line numbers from the submitted JavaScript, excluding internal wrappers and headless setup, including after wait. Internal wrapper and controller frames are omitted from new cells' failures; error messages still share the existing output budget. Code Mode does not accept TypeScript source or produce compiler diagnostics.

Use targeted model transport logging when code mode behaves differently from a normal tool run:

APUS_DEBUG_CODE_MODE=1 \
APUS_DEBUG_MODEL_TRANSPORT=1 \
APUS_DEBUG_MODEL_PAYLOAD=tools \
APUS_DEBUG_SSE=events \
apus gateway

For payload-shape debugging, use APUS_DEBUG_MODEL_PAYLOAD=full-redacted. This logs a capped, redacted JSON snapshot of the model request; use it only while debugging, since prompts and message text can still appear.

For stream debugging, use APUS_DEBUG_SSE=peek to log the first five redacted SSE events. Code mode also fails closed if the final provider payload does not contain exactly one exec, one wait, and only approved direct-only tools after the code-mode surface has activated.