Understand admission errors
Symptom
Your client receives an error from ‹source›.swarmvia.cloud (or your custom
domain) with a swarmvia error body, often before any upstream latency.
Common statuses
401 unauthorized
The caller's credential was missing or rejected: an access key, a JWT, or a
Cloudflare Access token. Auth failures never take a
concurrency slot. The message field says which check failed:
message |
What it means | What to do |
|---|---|---|
missing access key |
The source requires a key and none was sent. | Send the key in X-Swarmvia-Key. |
legacy access key no longer accepted |
The key starts with nb_live_. Those older keys stopped working on November 7, 2026. |
Mint an access token instead. For an integration, use a Control API token; see Refresh access tokens before they expire. |
invalid access token |
The key is not a valid access key: it does not start with sv_at_, it is malformed, its signature does not verify, or it was issued for a different source. |
Send the key exactly as it was returned, to the source it was minted for. If it still fails, mint a new one. |
access token expired |
The key is past its expires_at. |
Mint a new key: agents start a new session with start_source_session (up to 7d with expires_in); integrations call the Control API again. Refresh before expiry to avoid this (how). |
access token revoked |
The key was revoked with revoke_source_session, the Control API, or on the Access tab, or the member it acts for left the organization. |
Mint a new key. If you did not revoke it, ask the source's owner why it was revoked. |
{
"error": "unauthorized",
"message": "access token expired"
}JWT and Cloudflare Access failures carry their own messages. Check the issuer, audience, and token expiry against the source's Access settings.
403
IP policy rejection (a blocked range, or outside the allowed ranges), or the
source's custom-hostname lock is on and you called
the canonical *.swarmvia.cloud host.
400
Origin selection failed. Send a valid X-Swarmvia-Origin that exactly matches a
configured origin, or ensure the path matches a configured path prefix.
413 payload_too_large
The body exceeds a size limit for bodies that must be fully read. With
origin verification
on and no usable Content-Length, swarmvia cannot bind the length of a
streamed body over 10 MB. With a correct Content-Length, origin
verification signs the first 1 MB and streams the rest (no size-based 413).
Shrink the payload, or send Content-Length on large origin-verified uploads.
429 too_many_requests
The request never entered an open wait: the
source queue is already full, the caller set X-Swarmvia-No-Queue, or the RPM
gate is overloaded. Honor Retry-After when present. Raise queue depth /
concurrency only within plan limits, or shed load at the client.
504 queue_timeout
The open wait ran out before a slot freed.
Body message: Source queue timeout: no slot available within the wait budget.
Raise queue timeout, raise concurrency, or lower load.
504 request_timeout
The request held a slot past the
request timeout. Body message:
Source request timeout: exceeded the slot lease. Raise it if the upstream call
is slow, or fix hung upstream work. A response whose headers already arrived
cannot turn into a 504: if its body is still streaming at the request timeout,
the body is cut off instead. Both timeout responses include
x-swarmvia-* governor headers (total-ms, slot/queue stats) so you can tell
them apart from a Cloudflare HTML 524.
424 credential_needs_reauthorization
The source's OAuth 2.0 credential was rejected by its token endpoint. The
reason field carries the provider's code, for example invalid_grant for a
revoked refresh token. Retrying will not help. Open reconnect_url and rotate
the credential. See Credential health.
{
"error": "credential_needs_reauthorization",
"message": "The upstream token endpoint rejected this source's credential (invalid_grant). Reconnect or rotate it in the dashboard.",
"reason": "invalid_grant",
"reconnect_url": "https://swarmvia.com/sources/orders-acme/reconnect"
}403 credential_requires_member_key
The source uses a per-member credential: each call is made with the connected account of the member the key acts for. This key is a machine key. Mint one with Acts for: Me, or connect the agent over MCP so its session keys act for you.
424 credential_missing
A managed source has no credential attached. Attach one on the source's Access tab.
503 credential_unavailable
The token endpoint for the source's OAuth 2.0 credential is failing (5xx,
throttled, or unreachable), or, with reason: vault_error, swarmvia briefly
could not read the stored credential. Honor Retry-After; swarmvia backs off
and recovers on its own. The origin was not called.
MCP sources
An MCP source answers GET /tools and POST /tools/call and nothing else. Its
own errors:
| Status and error | What it means |
|---|---|
403 tool_not_allowed |
The source's tool list does not include this tool. GET /tools shows the ones it does. The server was not called. |
403 tool_not_read_only |
The key is read-only, and the server does not mark this tool as read-only. A connector calls every tool checked on the source page, read or write. Reconnecting the connector does not change that list. |
400 invalid_tool_call |
The server refused the call itself: an unknown tool or arguments that do not match its schema. code carries the server's JSON-RPC code. |
424 credential_needs_reauthorization with reason: upstream_rejected_token |
The server refused the token swarmvia sent. Reconnect (OAuth) or rotate the stored token. |
424 credential_insufficient_scope |
The server needs more access than the connection granted. required_scope names it; reconnect to grant it. |
424 credential_missing with reason: upstream_requires_auth |
The server needed no authorization when the source was created and now does. Connect a credential. |
429 upstream_throttled |
The server is rate-limiting. Honor Retry-After. |
502 mcp_error / mcp_protocol_error |
The server failed the request, or answered in a way that is not valid MCP. |
A tool that ran and failed is not an error at this level: the call returns
200 with result.isError: true, the same as the server sent it.
503 pool_suspended
Body message: This source is suspended. Billing or policy suspension. Check Billing and source status in the
dashboard.
501 pool_not_configured
Body message: This source has no upstream routing configured yet. The
source is not configured yet. Re-save the source in the dashboard
or wait a moment after create.
What to check
- Source Access settings vs the headers you send
- Concurrency / RPM settings and current live status on the source page
- Access Logs for the reject reason and timing fields
- Whether you intended proxy vs lock API