8.8 Limits inside the sandbox and diagnosing failures
A custom service runs under hard, host-enforced limits, and its failures surface as structured errors. Knowing the limits and the error vocabulary turns "it doesn't work" into a quick diagnosis.
The limits
Every invocation runs under (operator-configurable; defaults shown):
- Wall clock — 30 s for a service. Exceeding it terminates the invocation
with
limit_exceeded(wall_clock_ms). - Memory — a heap cap kills an allocation bomb the same way
(
limit_exceededmemory_bytes), with no impact on the process or other tenants. - Outbound calls — budgeted (default 64 per invocation).
- Body materialization — capped (default 100 MB).
Repeated breaches trip the tenant's circuit breaker (9.5), so pathological code can't keep re-occupying engine threads. Design handlers to finish well inside these bounds; treat termination as a possibility, not an impossibility.
The failure vocabulary
When a custom service misbehaves, the problem+json code tells you what
happened:
| Status / code | Meaning | First thing to check |
|---|---|---|
502 contract_violation — "bundle error: …" |
The module failed to evaluate | A missing global (check 8.3's supported list) or top-level I/O |
502 contract_violation — "handle rejected: …" |
The handler threw; rejection text included | Your handler logic; the included message |
403 capability_denied (with a capability field) |
Used an ungranted/misnamed capability, or a non-allowlisted host | The grant name matches ctx.request's; the host is in the allowlist (8.5) |
503 limit_exceeded (wall_clock_ms/memory_bytes) |
Runaway loop or allocation; isolate terminated cleanly | An infinite loop, unbounded data, a missing base case |
501 engine_unavailable |
The server build lacks the engine for this bundle type, or no HTTP adapter is wired for httpOut |
The server was built with the right feature (js/wasm/http) |
404 "deployed code … not found" |
The mount's code: ref isn't deployed to this tenant |
Deploy to the tenant; refs are per-tenant (8.7) |
A diagnostic flow
- Read the
codeanddetailin theproblem+jsonbody — they're specific (the JS exception text is included for502s). - Grab the
X-Trace-Idand look up that trace in the logs (Part 10) — yourconsole.log/ctx.loglines are stamped with the same trace, so they line up with the failing request. - For
capability_denied, check thecapabilityfield against yourgrantskeys and the host allowlist — name mismatches are the most common cause. - For
limit_exceeded, look for unbounded loops or data; remember timers are virtual (a "sleep" won't burn wall time, but a busy loop will).
Logs are your friend
Because sandbox console.log/ctx.log output is captured into the tenant's
structured logs with the invocation's trace id, the log reader (Part 10) is the
primary debugging tool for deployed code — much like a browser console, but
server-side and correlated to each request.
That completes custom services. Part 9 zooms back out to the cross-cutting HTTP behavior — discovery, errors, idempotency, caching, and limits — that applies to every service, custom or prebuilt.
← Previous: 8.7 Versioning, rollback, mounting · Manual home · Next: 8.9 Loadable storage adapters →