Limits and errors
What bounds a request, what a visitor sees when something fails, and what your code can catch. Operator-side defaults and the files that define them are in default policies. Numbers below are the code's defaults; an administrator's site policy can only lower the per-execution limits, and a manifest can only lower the timeout and memory (Manifest).
Per-execution limits
ExecutionLimits::default() in crates/core/src/execution.rs:
| Limit | Default | What happens when exceeded |
|---|---|---|
| Wall time | 1,000 ms | Execution is terminated: HTTP 504. No catch or finally runs. |
| JS memory | 32 MiB | HTTP 500. |
| Request body | 1 MiB | Edge answers 413 before your code runs. |
| Response body | 4 MiB | HTTP 500 (response too large). |
| Host calls | 64 | The next call rejects with QUOTA_EXCEEDED. |
| Database rows | 100,000 | A call rejects with QUOTA_EXCEEDED. |
| Egress bytes | 8 MiB | A call rejects with QUOTA_EXCEEDED. |
| Mail messages | 10 | A call rejects with QUOTA_EXCEEDED. |
| Storage write bytes | 16 MiB | A call rejects with QUOTA_EXCEEDED. |
| Host buffer bytes | 16 MiB | A call rejects with QUOTA_EXCEEDED. |
| Password hash/verify calls | 2 (fixed) | quota_exceeded from microhost/auth. |
| Console output | 64 KiB | Later lines are dropped silently. |
getRandomValues |
65,536 bytes per call | RangeError. |
| Modules | 256 modules, 8 MiB of source | The import fails. |
Notes:
- Every host call counts, including each page of a database query, each session operation, each auth call and the SHA-256 that session tokens use. Plan your handlers around 64 calls.
- Host calls run one at a time through the engine bridge.
Promise.alldoes not make database or network work parallel. - Fuel metering is not enabled in the production runtime composition. CPU is bounded by the wall-time limit.
- These defaults are not performance or isolation guarantees across engines.
- Each site also has a request rate (default 60 requests per 60 s; HTTP 429) and a concurrency limit (default 4 simultaneous executions).
Per-call limits
| Call | Limit |
|---|---|
Host-call timeouts (a slow call rejects with HOST_UNAVAILABLE; the script keeps running) |
SHA-256 1 s, env 1 s, admin verify 1 s, auth and storage 2 s, database query or execute 5 s, database transaction 10 s, mail 10 s, fetch 15 s. |
| Database broker | SQL text 64 KiB, 999 bound parameters, a query or execute at most 2 s, a transaction at most 5 s and 256 statements, 4 concurrent connections per site, 16 MiB per string, blob or row. The shared transport accepts at most 100 statements per transaction and 1 MiB of request payload. |
| Storage | Key 1,024 bytes; list returns at most 1,000 names; site quota 256 MiB and 10,000 objects by default. |
fetch |
Port 443, exact allowed hosts, at most 3 redirects, request and response bodies 1 MiB each (production composition), 5 s connect, 30 s total. |
| By default 10 recipients and 256 KiB per message; outbox 100 queued messages and 5 MiB per site. | |
| Wire envelopes | One host call, request or reply, is at most 16 MiB encoded (the Linux worker frame cap). Binary data is carried as U+0000..U+00FF strings, so escaping can make an encoded payload several times the raw size. The shared host-call envelope limits a BLOB value to 4 MiB and a storage payload to (16 MiB - 4 KiB) / 6 bytes (about 2.7 MiB); engine transports that predate the shared envelope may apply different limits, so keep single objects well below 2 MiB. |
| Sessions | User id 256 bytes, data 1,024 bytes of JSON, lifetime 1 to 2,592,000 s, Cookie header read up to 4,096 bytes, Set-Cookie value at most 4,096 bytes. |
| Auth | Password 1,024 bytes, 4 concurrent hashes platform-wide, 2 s deadline. |
Platform request limits
Defaults: headers 16 KiB, request target (path plus query) 8 KiB, request body 1 MiB read within 30 s, header read timeout 10 s, 60 requests per 60 s per client IP.
Build and deploy limits
| Item | Limit |
|---|---|
| Manifest | 64 KiB, 256 routes, 32 external hosts, 64 workspace database names |
microhost.config.js build |
2 s, 50,000,000 fuel, 32 MiB, 64 KiB output, 1,000 files listed, 1 MiB reads |
| Migrations | 128 files, 256 KiB each, 2 MiB total, 15 s |
Static files (public/) |
Streamed from disk in 256 KiB chunks, so a file of any size that fits the 200 MiB extracted limit is served with constant memory. Range (one range), HEAD, ETag and 304 are supported. |
External files (public/ files the platform moved to an external store) |
Same URL, headers, Range, ETag (the quoted SHA-256) and 304 as local files. At most 8 open reads from the store per site and 32 on the platform at once; reads served from the platform's cache do not count. Store timeouts: connect 5 s, first byte 10 s, idle 30 s. See External storage. |
| ZIP | Admin API upload 32 MiB by default; extracted 200 MiB, 10,000 files, depth 16, ratio 100, 60 s |
| Release retention | limits.keep_releases, default 5 (2 to 100); the active release is always kept |
| Admin extensions | 4 per site, 8 pages, 32 requests, 24 elements per page, 32 KiB input, 256 KiB response, 5 s |
What visitors see
Visitors only ever see generic texts. Details go to the operator log and the site log (the console output of your handler, capped at 64 KiB per execution).
Edge
| Condition | Status |
|---|---|
| Malformed path or Host | 400 |
Unknown host, hidden path, /_admin, missing file, no script, refused file |
404 (generic body) |
| Static file with a method other than GET or HEAD; route with a method that is not allowed | 405 with Allow |
| Body read timeout | 408 |
| Body above the limit | 413 |
| Request target above 8 KiB | 414 |
| Headers above the limit | 431 |
| Client-IP or site request budget exhausted | 429 |
| Header read timeout | Connection closed |
| Internal failure while serving a file | 500 |
| A file that lives in external storage, and the store cannot be reached, the object is gone, or the store's concurrent-read cap is reached | 502 Bad Gateway (generic body, nothing about the store) |
An external file never falls back to another file or to a stale copy: it is served from the platform's cache or from the store, or it is a 502. Local files of the same site are not affected. A HEAD or a conditional request (If-None-Match) for an external file is answered from the platform database, so it still works while the store is down.
For a known site, these answers (except the malformed, 414, 431 and per-IP 429 ones) can be replaced by your own pages: see Error pages.
Execution
| Condition | Status and text |
|---|---|
Uncaught exception or rejected promise, a thrown sdk_module_disabled, a dynamic import, memory limit, response too large, engine failure |
500 Internal Server Error |
Handler resolved to a non-Response, invalid status, illegal header name or value (CR or LF), Set-Cookie over 4,096 bytes |
502 Bad Gateway |
| Timeout | 504 Gateway Timeout |
Capability refused at load (import outside the release, or a public/ file) |
403 Forbidden |
Dispatch not available (serve --dev) |
501 Not Implemented |
A handler that catches a coded host error can answer however it likes; only uncaught failures produce these generic pages.
Error codes
Your code sees three families of codes. Always branch on error.code, never on the message (messages are generic and carry no paths or SQL).
Host-call errors (ctx.db, ctx.storage, ctx.env, ctx.mail, fetch, microhost/session): the thrown Error has an uppercase code.
| Code | Class | Meaning |
|---|---|---|
CAPABILITY_DENIED |
CapabilityError |
The grant is absent, revoked, or the destination or name is not allowed. Checked on every call. |
QUOTA_EXCEEDED |
QuotaError |
A budget above is exhausted. |
INVALID_INPUT |
TypeError |
The call received invalid arguments (also thrown for client-side argument checks). |
HOST_UNAVAILABLE |
HostError |
The backing service is unavailable or the call timed out. |
HOST_INTERNAL |
HostError |
An internal host failure. |
invalid_admin_request |
AdminRequestError |
verifyAdminRequest failed. |
SDK module errors use lowercase snake_case codes:
| Code | Module | Meaning |
|---|---|---|
db_use_sql_template, db_multiple_rows, db_duplicate_column, db_no_such_column, db_where_required, db_invalid_direction |
microhost/db |
See Database SDK. |
capability_denied |
microhost/db, microhost/session import |
ctx.db is absent or revoked at the call; or the import was refused. |
sdk_module_disabled |
any module import | The module is not requested or an administrator disabled it. |
invalid_input, quota_exceeded, host_unavailable, host_internal, capability_denied |
microhost/auth |
Thrown as Error with name HostError; see Auth and sessions. |
microhost/session rejects bad arguments with INVALID_INPUT (uppercase, TypeError) and passes broker errors through with their uppercase codes.
Admin API codes of external storage (deploys and the storage actions; see External storage):
| Code | Status | Meaning |
|---|---|---|
release_assets_unavailable |
409 | A deploy, publish or rollback refused to activate a release because an object it needs is missing from the store, has another size, or the store could not be reached. The previous release stays live. Run verify, fix the store, deploy again. |
operations_unavailable |
503 | verify and reconcile are not available on this server (development mode, or no secret vault). |
store_in_use |
409 | The store's location cannot change, or the store cannot be removed, while files reference it. |
Revocation. A grant revoked before a call's policy check makes that call fail with capability_denied or CAPABILITY_DENIED, even in the middle of an execution (for example between two pages of a query). There is no grace period; a call already past its check may finish. If the platform cannot read the current policy it fails closed with the same code.
Job limits
Scheduled and background jobs run with their own limits: 30 seconds wall clock by default (10 minutes at most, timeoutMs), 64 MiB memory, 1,000 host calls, 1,000,000 database rows and 32 MiB outbound. They run in a separate capacity pool (2 at once on the platform, 1 per website). The run states and error codes are listed in Scheduled jobs.
Debugging checklist
| Symptom | Check |
|---|---|
| 501 on a script endpoint | You are on serve --dev, which serves static files only. |
| 404 | Host mapping, active release, route and script paths; hidden path (a dot segment); a /_admin path. |
| 405 | Route method list; handler checks; a static file or exact route shadowing your path. |
| 403 | A refused import (outside the release, or public/). |
| 429 | Per-IP or per-site request budget. |
| 500 | Uncaught exception, sdk_module_disabled, memory, response over 4 MiB, dynamic import. Read the site log. |
| 502 | The handler did not return a Response, or a header or status is invalid. For a static file: it lives in external storage and the store failed (ask the operator to run verify). |
| 504 | Wall time exceeded (default 1 s); hashing, large queries or slow fetch calls add up. |
ctx.db is undefined |
Not requested in the manifest, or not granted. |
capability_denied from microhost/db |
ctx.db absent or revoked. |
| Import fails | Relative .js path, private namespace, module limits, sdk list. |