Errors & status codes
The single source for CoreSpeed HTTP status codes, error codes, error envelopes, and MCP isError results.
Every status code and error code returned by the endpoints in this reference is listed here. Other pages link to this one instead of repeating the table, so this is the copy to trust if you find a disagreement.
A CoreSpeed call fails at one of two layers. An HTTP failure — a 4xx or
5xx status — means the request itself was refused. A tool failure is an
HTTP 200 whose JSON-RPC result carries isError: true: the request was
authorized and the tool refused or failed. Both carry a machine-readable code;
branch on it, and treat the message or text as prose for humans.
The HTTP envelope
Every HTTP failure uses one nested envelope — error is an object:
{
"error": {
"type": "authentication_error",
"code": "missing_authorization",
"message": "Authorization header or x-api-key is required"
}
}code is the stable value to branch on. type is derived from the status:
| Status | type |
|---|---|
400, 409, 411, 413, 415, 422 | invalid_request_error |
401 | authentication_error |
402 | payment_required |
403 | forbidden |
404 | not_found |
405 | method_not_allowed |
429 | rate_limit_error |
500 | server_error |
502, 503 | api_error |
A route adds its own facts inside error: field on a validation failure,
request_id on a 500, and so on. Rate limiting — and any 503 that knows
when to come back — also sets the Retry-After header and a top-level
retry_after sibling. Read the header or the sibling — not
error.retry_after, which does not exist:
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 60s."
},
"retry_after": 60
}Two surfaces answer with a shape of their own:
- A signed artifact download (
GET /artifacts/…) answers with RFC 9457application/problem+json. - The MCP transport answers envelope-level mistakes with a bare JSON-RPC error object, below.
Transport errors on /mcp
Identity, rate limiting, and the body-size limit run first: POST /mcp
checks them ahead of the transport, so an unauthenticated caller gets the
nested 401, a throttled one gets 429, and a body over 5 MiB gets
413 payload_too_large — the envelopes above — no matter what the request
body or headers look like.
Only once the caller is identified does the Streamable HTTP transport validate
the envelope itself. Those failures answer with a bare JSON-RPC error object —
{ "jsonrpc": "2.0", "error": { code, message }, "id": null } — not the
envelope above:
-32000Accept must list both application/json and text/event-stream. Sending
only application/json fails here, which is why every sample sets both.
-32000Content-Type must be application/json.
-32700Parse error — malformed JSON, or a body that is not a valid JSON-RPC message.
-32600A JSON-RPC batch (array body). CoreSpeed rejects arrays ahead of the transport so one rate-limit slot cannot carry an unbounded number of tool calls.
-32020A request on the 2026-07-28 protocol revision whose Mcp-Method or
Mcp-Name header is missing or disagrees with the body. Nothing ran.
-32601subscriptions/listen. CoreSpeed publishes no events, so it refuses the
method.
HTTP status codes
These can come from any authenticated route, ahead of the route's own codes (listed per route in the next section).
invalid_requestThe body, query, or path parameters failed validation, or the body is not
JSON at all. error.field names the first offending field when there is one.
Fix the request — do not retry it unchanged.
missing_authorizationNo Authorization and no x-api-key header. On /mcp the response also
carries a WWW-Authenticate header pointing at the protected-resource
metadata, which is how OAuth-capable clients start browser sign-in.
invalid_jwtA bearer JWT failed verification. Which token to renew depends on which one
you sent: a user session JWT is refreshed against the session issuer, while an
MCP OAuth token on /mcp has its own issuer and lifecycle and is renewed by
re-running the client's browser sign-in — refreshing the session does nothing
for it. Both failures answer with this one code.
invalid_api_keyThe API key is unknown, revoked, or expired. Replace it — do not retry.
no_active_orgThe caller authenticated but no organization resolved. Answered by the key, agent, organization, billing, and connector routes. Open the dashboard once to finish setup, then sign in again so the client picks up a token that carries the organization.
It is not an /mcp status: /mcp mounts no HTTP wallet gate, so a
metered tools/call answers 200 with isError instead — see the tool
codes below.
payment_requiredThe organization wallet has no credit available. Billable operations
stop before execution; discovery and account reads still work. Topping up
clears it. Over HTTP the media upload routes answer it; on /mcp a metered
tool answers it as a tool result (below).
key_spend_limit_exceededThis API key reached its monthly spend cap. Raise the cap or wait for the reset. Caps are request-boundary guardrails, so a call already in flight can finish above the remaining amount.
org_suspendedAdministrative suspension. Every organization-scoped route answers it,
/mcp included, before anything runs. Adding balance does not clear it —
contact support.
agent_suspendedThe credential belongs to an agent that is suspended. The key itself is fine
— resume the agent (its owner or a holder of agents:manage, via manage__agents_update or
the dashboard) instead of rotating anything.
agent_retiredThe agent was retired and its keys are being revoked; once the revocation
lands the same key answers 401 invalid_api_key. Nothing restores a retired
agent — mint a new one.
api_key_cannot_mintAn API key asked to mint a key (POST /api-keys, POST /agents/:id/keys).
A key's spend cap does not carry to the keys it would mint, so minting is
done from a signed-in session or an MCP sign-in. Every other route answers
a key as its principal, with the permissions the key was minted with.
member_principal_requiredAn agent principal called an act that is a member's own: creating an agent
(POST /agents), the environment writes, or the /me user actions
(/me/sync, /me/orgs, /me/provision, /me/analytics-preferences). A
member's own key is admitted like their session.
api_key_cannot_decidePOST /approvals/:id/decide was called with an API key (the dashboard's
GraphQL mutations answer API_KEY_CANNOT_DECIDE the same way). An approval
is a person's click between an agent and its write, and a member key is
the credential agents run on; decide from the dashboard, Slack, email, or
the Tie menu bar app.
insufficient_roleThe route needs a permission the caller does not hold; permission names
it (for example members:manage or billing:manage).
ceiling_exceededPOST /api-keys asked for a permission the caller's token cannot hand on;
missing names the slugs. A key never carries more than the token that
minted it.
endpoint_not_foundUnknown path, a connector id that is unknown or not offered on this
environment (the two are deliberately indistinguishable — see
Get connector), or a retired
per-connector / per-engine MCP URL. Call the unified POST /mcp.
Allow: POSTGET /mcp. The endpoint is POST-only — there is no SSE downstream. This
response has no body and no error code: only the Allow header.
multiple_accountsDELETE /connectors/:id matched more than one of your private accounts.
Remove one directly via DELETE /connectors/:id/accounts/:accountId, or use
manage__accounts_remove with an alias.
rate_limit_exceededToo many requests in the current 60-second window. Two independent dimensions
are metered: per API key, and per user for session callers — so one runaway key
is throttled without affecting the rest of the organization. Wait out
Retry-After (advisory, matches the window) before retrying; the body repeats
it as a top-level retry_after.
platform_db_unavailableThe API-key authority, the organization's billing standing, or (on /mcp)
the caller's tool surface could not be read. CoreSpeed fails closed
rather than allowing an unverified key or an unjudged metered call, so this
is a transient infrastructure state, not a credential problem — retry with
backoff.
internal_errorAn unexpected gateway error. The body carries error.request_id; retry with
backoff and quote the id to support.
Codes by route
What each route family adds to the table above. Every route that talks to the
payment provider can also answer 503 payment_provider_unavailable (retry
shortly) or 503 billing_unavailable (billing is not offered on this
environment).
| Route | Status and code |
|---|---|
POST /api-keys | 400 invalid_request (field: permissions — not an array of strings) · 400 unknown_permission (unknown names the slugs) · 401 session_client_id_missing (sign in again from a CoreSpeed client) · 403 ceiling_exceeded (missing names the slugs) · 404 WALLET_NOT_FOUND · 404 environment_not_found (environment names none of yours) |
PATCH /api-keys/:id | 403 agent_self_escalation (an agent key cannot change key settings) · 404 api_key_not_found |
DELETE /api-keys/:id | 404 api_key_not_found — a key outside the caller's scope reads as absent |
POST /api-keys/:id/rotate | 403 ceiling_exceeded (the key carries a permission the caller cannot hand on; missing names it) · 404 api_key_not_found · 404 WALLET_NOT_FOUND |
GET /agents/:id | 404 agent_not_found |
PATCH /agents/:id | 403 insufficient_role (the owner or agents:manage; a transfer needs agents:transfer) · 404 agent_not_found · 409 agent_already_retired |
POST /agents/:id/keys | 400 agent_key_permissions (an agent's key carries no permissions) · 401 session_client_id_missing · 403 insufficient_role · 404 agent_not_found · 404 WALLET_NOT_FOUND · 404 environment_not_found (environment names none of the agent's) · 409 agent_not_active |
POST /agents/:id/retire | 403 insufficient_role · 404 agent_not_found |
POST /me/provision | 403 MEMBERSHIP_REVOKED · 409 provisioning_conflict · 502 identity_provider_error |
POST /me/orgs | 403 org_create_requires_payment_method · 409 provision_required · 502 identity_provider_error |
POST /me/sync | 502 identity_provider_error |
/me/org members and invitations | 402 plan_member_limit and 403 member_limit_reached (inviting past the plan's seats) · 404 not_found (member or invitation) · 409 last_admin (the organization must keep one admin) · 502 identity_provider_error |
POST /checkout/subscribe | 404 PLAN_NOT_FOUND · 404 org_not_found · 409 ALREADY_PRO · 409 STRIPE_CUSTOMER_INCONSISTENT |
POST /checkout/topup | 403 topup_requires_subscription · 404 PLAN_NOT_FOUND · 404 org_not_found · 409 STRIPE_CUSTOMER_INCONSISTENT |
POST /checkout/portal | 404 no_billing_account |
POST /checkout/payment-method-setup | 404 org_not_found · 409 STRIPE_CUSTOMER_INCONSISTENT |
/customers/me/* billing profile and payment methods | 400 no_org_customer · 404 payment_method_not_found · 409 payment_method_in_use (a method that funds an active subscription cannot be removed) |
POST /connectors/org | 400 invalid_slug · reserved_slug · invalid_url · unsupported_auth_mode · token_required · invalid_headers · custom_headers_unavailable · preregistered_client_required — 403 admin_required · 409 slug_taken · 409 oauth_registration_pending · 502 oauth_discovery_failed · 502 oauth_registration_failed |
POST /connectors/org/:slug/refresh | 403 admin_required · 404 not_found · 409 not_connected / needs_reauth / unauthorized (the credential needs reconnecting) · 429 cooldown (one refresh per 60 s, with Retry-After) · 502 snapshot_failed · 503 kv_unavailable (the refresh cooldown or the snapshot cache could not be read or written; retry) |
DELETE /connectors/org/:slug | 403 admin_required · 403 environment_active (a key bound to an environment) · 409 oauth_registration_pending · 409 connector_changed (the registration changed since you read it) · 404 endpoint_not_found |
GET /connectors/org/:slug | 404 endpoint_not_found for an unknown slug |
DELETE /connectors/:id | 409 multiple_accounts — you have more than one private account of this connector; remove one by id or alias |
DELETE /connectors/:id/accounts/:accountId | 404 not_found — no such account, or not one you may remove (with a key bound to an environment: not one of the environment's) |
POST /mcp/env/:name | 404 environment_not_found (no environment of yours by that name — a ping too) · 403 environment_mismatch (the key is bound to another environment) |
/me/environments, /me/environments/connections | 403 member_principal_required (an agent principal on a write) · 400 invalid_request (name is not 1–63 lowercase letters, digits or inner hyphens; a malformed entries or tools) · 400 connection_not_reachable (connection_ids the owner cannot use) · 400 unknown_tools · 400 tools_empty · 403 agent_not_manageable · 404 environment_not_found (none you may manage) · 404 agent_not_found · 409 environment_name_taken · 409 environment_in_use (keys: active keys still bound; revoke them first) |
POST /connectors/:id/accounts/:accountId/grants | 400 invalid_request (grantee_id or tools) · invalid_grantee · grantee_not_in_org · unknown_tools · tools_empty — 404 not_found (no such account, or not one you may share) · 409 not_shareable (this connector's personal accounts stay private) |
DELETE /connectors/:id/accounts/:accountId/grants/:granteeId | 404 not_found · 404 grant_not_found (the account is not shared with that grantee) |
PUT /connectors/:id/client | 400 invalid_request (client_id missing) · 403 forbidden (an organization admin only) · 409 client_id_shared (a Microsoft connector's app is already registered for a sibling connector, named in sibling) · 404 endpoint_not_found (this connector takes no organization client) |
DELETE /connectors/:id/client | 403 forbidden (an organization admin only) · 404 endpoint_not_found (no organization client to remove) |
PUT <upload_url> | 400 content_type_required · invalid_content_length · content_length_mismatch · upload_ticket_mismatch — 403 no_active_org · 403 capability_disabled · 404 upload_ticket_invalid · 405 method_not_allowed · 411 content_length_required · 413 payload_too_large · 413 upload_quota_exceeded · 502 storage_error · 502 file_record_failed · 503 quota_unavailable · authorization_unavailable · upload_capacity_exhausted · upload_ticket_unavailable |
MCP tool errors
A tool failure is not an HTTP failure. The transport answers 200; the
JSON-RPC result carries isError: true, one text block the agent reads, and
the machine-readable half in structuredContent.error:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "GitHub rate-limited GET /search/repositories with 429 (search_repositories); retry after 30s"
}
],
"structuredContent": {
"error": { "code": "rate_limited", "status": 429, "retry_after_seconds": 30 }
},
"isError": true
}
}Always check result.isError in addition to the HTTP status, then branch on
structuredContent.error.code. Beside code, error carries only facts that
are safe to publish — a provider's status, its request_id, a
retry_after_seconds, the aliases to choose from — never a provider's body or
a credential.
One refusal keeps an older shape that clients already parse: the pre-flight
hold's JSON envelope is the text itself, with no structuredContent, and
the hold also names itself in _meta["io.corespeed/hold"] as
{ code, refusal }:
{
"content": [
{
"type": "text",
"text": "{\"error\":{\"type\":\"payment_required\",\"message\":\"…\",\"code\":\"payment_required\"}}"
}
],
"isError": true,
"_meta": { "io.corespeed/hold": { "code": "payment_required", "refusal": "OrgBelowSpendCutoff" } }
}An approval-gated write answers with a receipt instead — isError: true, the
approval id in the text, and _meta["io.corespeed/approval"] — and
manage__approval_wait returns the real result; see
Approvals.
Codes on every tool
-32602A tool name that is unknown or not on this caller's surface. This one is a
JSON-RPC error (Tool <name> not found), not a result, so check for
error as well as isError. A typo in params.name never surfaces in the
HTTP status.
Input validation errorArguments that fail the tool's inputSchema. The result has isError: true
and the text Input validation error: Invalid arguments for tool <name>: …,
with no structuredContent. The MCP SDK answers before the tool runs.
no_active_orgNo organization could be resolved for this sign-in. A browser MCP sign-in without an organization normally has one resolved — or created — on its first call, so this only remains when that could not complete (the identity provider or the platform database was unreachable). Retry shortly; if it keeps failing, open the dashboard once to finish setup, then sign in again from the MCP client.
payment_requiredThe organization is on a billing hold, caught before the metered tool
executed — the tool-level mirror of the 402 above.
key_spend_limit_exceededThe API key hit its monthly cap, caught before the metered tool executed.
org_suspendedAdministrative suspension. In practice /mcp answers the HTTP 403 above
before any tool runs; this tool-level mirror is a fallback.
platform_db_unavailableCoreSpeed could not read the organization's standing, a stored credential, or another record the call needs. Retry shortly.
api_key_cannot_mintmanage__keys_create or manage__agents_key_create was called with an API
key. A key does not mint keys; mint from the dashboard or a signed-in
client. Every other manage__* tool answers a key as its principal.
member_principal_requiredmanage__agents_create or an environments_* write was called by an agent
principal. Creating an agent and shaping environments are a member's own
acts; a member's own key is admitted like their session.
approval_unavailableThe approval service could not decide whether this write needs an approval, so the tool did not run. Retry shortly.
internalThe call failed inside CoreSpeed. error.request_id identifies it; retry
once, and quote the id to support if it fails again.
invalid_tool_resultThe tool produced a result that breaks its own declared output — a CoreSpeed
defect, reported like internal, with request_id.
no_active_org, payment_required, key_spend_limit_exceeded,
org_suspended, and a platform_db_unavailable about billing standing are the
pre-flight hold, answered in the JSON-in-text shape above.
api_key_cannot_mint, member_principal_required, approval_unavailable,
internal, and invalid_tool_result are in structuredContent.error.
Codes on every connector
Each connector's tools answer in that connector's name, with these codes:
| Code | Meaning | Move |
|---|---|---|
not_connected | No account of this connector is connected for this caller, or none with that alias. | Connect it in Dashboard → Connectors. |
needs_reauth | The provider rejected the stored grant, or it can no longer be renewed. The account is now marked needs_reauth. | Reauthorize the account. Do not rotate the CoreSpeed key. |
ambiguous_account | More than one account is connected; error.aliases lists them. Nothing was sent. | Pass account with one of the aliases. |
account_not_found | No connected account has that alias; error.alias and error.available. | Pass one of available. |
tool_not_granted | The account is shared with you for some tools only, and this tool is not one of them; error.alias and error.allowed. | Ask the account's owner to extend the share. |
tool_not_in_environment | The session runs in an environment that leaves this account or tool out; error.environment, error.alias and error.allowed (empty when no account of the connector is in it). | Edit the environment from a session outside it, or use another URL or key. |
credential_incomplete | The stored connection is missing a value the provider needs (an account id, a domain). | Reconnect the account. |
credential_undecryptable | The stored credential could not be read. | Reconnect the account. |
token_refresh_failed | The provider's token endpoint refused or failed to renew the access token (error.status when it answered). | Retry; if it persists, reconnect. |
not_configured | This CoreSpeed environment lacks the app registration the call needs. Not your account. | Report it to support; reconnecting does not help. |
platform_db_unavailable | CoreSpeed could not reach its platform database to load the credential. | Retry shortly. |
upstream_error | The provider refused the request. The text carries its status, the route, and its redacted reason; error carries status for an HTTP refusal, and request_id and retry_after_seconds when the provider sent them. | Fix the request, or act on the provider's reason. |
rate_limited | The provider rate-limited the call (status, and retry_after_seconds or rate_limit_reset_at when known). | Wait, then retry. |
upstream_unreachable | The provider could not be reached. On a write the text says the change may still have been applied. | Check before retrying a write. |
upstream_response_invalid | The provider answered with something that is not the expected response (error.status when it had one). | As above. |
cancelled | The call was cancelled before the provider answered. | Check before retrying a write. |
Some connectors add codes of their own:
| Connector | Code | Meaning |
|---|---|---|
| Atlassian, Auth0, Bitbucket, Google Drive, Meta Ads, Slack, X, YouTube | scope_not_granted | The connection lacks a scope this tool needs (error.missing when the connector can name it); reconnect to grant it. |
| Blackbaud, Bluesky, Canvas, Slack, Stack Exchange, Twitch, Facebook, Instagram, Pinterest, Reddit, Reddit Ads, Salesforce, WhatsApp | not_configured | This environment lacks the connector's own app registration, key, or approval (for the Composio-managed seven, error.reason says whether the managed backend is unconfigured or switched off). Not your account. |
| Atlassian, AWS, Bitbucket, Capsule CRM, ClickUp, Crowdin, Dub, Gmail, Google Drive, Outlook, Outlook Calendar, Photon, Teams Chat, Twilio, YouTube, Zoho Mail | invalid_input | Arguments that conflict, or a pagination link not issued by this tool for this account; nothing was sent (error.field / error.reason where given). |
| Dynamics 365 | invalid_next_link | A next_link not issued for this organization and collection; nothing was requested. |
| Webex | invalid_cursor | A cursor that is not a next_cursor this tool returned for that collection; it was not followed. |
| Slack | invalid_arguments | An argument Slack cannot act on, such as a group DM for canvas access (error.field). |
| Atlassian | not_found | The Confluence page does not exist. |
| Atlassian | partially_applied | A Jira transition or sprint change landed part of its work (error.issue_key and error.transition_id, or error.sprint_id; error.comment_added_via, error.comment_id, error.failed_step, error.failed_code) — do not redo what landed. |
| X | not_found | No user has that handle; nothing was sent. |
| Bitbucket | not_found | The repository has no main branch yet, or no branch or tag with that name. |
| Photon | not_found | Photon answered 404 or 410 (error.status). |
| YouTube | not_found | The video or playlist to update is not on YouTube, or not visible to this channel. |
| Gmail | not_found, label_not_found | The message, thread, or draft (error.resource, error.id), or the label (error.label, error.field), does not exist. |
| Bluesky | handle_not_found | The handle does not resolve to an account (error.handle); nothing was written. |
| Bluesky | record_not_owned | A delete aimed at a record that is not the connected account's own (error.collection). |
| YouTube | concurrent_edit | The resource changed on YouTube while the update was prepared (HTTP 412); nothing was written — run the tool again. |
| Google Ads | partial_failure | Some operations committed and others were refused; error.committed lists what landed. |
| Gmail | partially_applied | The operation did part of its work before failing; error lists what was applied (forwarded, failed_source_ids, failed_with, or for a relabel applied, total, created_labels, failed_with) — do not redo those. |
| Zoho Mail | nothing_archived, partially_applied, scan_limit_reached | unarchive_emails: none of the ids were in the Archive folder; a later batch failed after earlier messages moved; or the thread was too long to walk. |
| Meta Ads | scope_not_granted | Graph refused with (#100) Requires <permission> for a permission the connector requests but the grant lacks (error.missing); reconnect to grant it. |
| Photon | scope_not_granted | The connection is a sign-in with Photon, and this tool's operation takes only an API key (key management, authorized apps, plan changes); nothing was sent. Connect Photon with a project API key or an Account Service Key. |
| Eventbrite | venue_address_incomplete | The venue lacks address fields Eventbrite requires (error.missing). |
| Google Drive | drive_not_empty, drive_emptiness_unconfirmed | A shared drive still holds items (error.trashed when they are in the trash), or Drive could not confirm that it is empty; nothing was deleted. |
| Atlassian, Google Drive | no_content, media_too_large | A download with no content, or past the size limit for a download or a stored file. |
| YouTube | unsupported_media_type, media_too_large | An upload of a type or size the tool does not take. |
| Atlassian, Google Drive | invalid_file_input, upload_quota_exceeded, upload_capacity_exhausted, quota_unavailable, storage_error, handle_storage_failed | Reading a file input or storing a download as an artifact, with the same meanings as in media__* below. |
| Google Ads, LinkedIn, Meta Ads, YouTube | invalid_file_input | A file input could not be opened, with the same meaning (and retryable) as in media__* below. |
| Auth0 | self_target_refused | The call would change the Auth0 application CoreSpeed itself connects through. |
| Crowdin | scan_limit_reached | A filtered project listing stopped before reaching the requested page; use unfiltered pagination. |
| ClickHouse Cloud | service_not_running | The Query API did not run the statement: the service is idle (error.state is idle; call again with wake_service: true) or stopped (stopped; start it first). Nothing ran. |
| Harvest | account_not_found | account_id is not one of the Harvest accounts this connection reached (error.available). |
| Timely | workspace_not_found | account_id is not one of the workspaces this connection reached (error.available). |
| X | free_write_limit_reached | The Free plan's daily write allowance is used up (error.limit); it resets at 00:00 UTC. |
| Facebook, Instagram, Pinterest, Reddit, Reddit Ads, Salesforce, WhatsApp | identity_mismatch | The stored connection was made for a different CoreSpeed identity, so it was not used; reconnect. |
| Slack | personal_account_required | The tool acts as the connecting member, and the selected alias is the organization bot; pass your personal account's alias. |
| Slack | reserved_channel, channel_id_required, approval_settings_unavailable | Tools may not write to the approval channel; a channel name was passed where an id is needed to check that; or the approval settings could not be read to check it (retry). |
| Datadog | mongodb_tag_resolution_unsupported | Datadog cannot resolve MongoDB instances by tag. |
| Stripe | docs_response_unverifiable | An API-reference-only search could not verify Stripe's response (error.reason). |
needs_reauth also covers each connector's own dead-credential signal —
Greenhouse's and Auth0's refused client credentials, Meta's Graph error 190,
an outdated Zotero key, an inactive Composio connection, a dead Slack user
token, an invalid Bluesky session — and credential_incomplete a stored API
key that no longer parses.
Slack answers a refusal with Slack's own error string in error.slack_error,
and forwards its hosted MCP server's isError results verbatim with a note
appended; Linear, monday.com, and Shopify read their GraphQL rate-limit codes
(RATELIMITED, complexity limits, THROTTLED) as rate_limited.
Vendor-hosted connectors (Datadog, Stripe, Sentry, and the other connectors
served from the vendor's own MCP server) forward the vendor's own isError
results verbatim. A failure on CoreSpeed's side of that connection answers
upstream_error (with status for an HTTP refusal, or required_scopes for
an insufficient_scope challenge), timeout (the upstream outcome is
unconfirmed), cancelled, needs_reauth, or upstream_url_refused. The
account codes in the first table above apply to them too.
Memory, media, web, social, and drive
memory__*
structuredContent.error is { code, message, … }, message repeating the
text.
| Code | Meaning |
|---|---|
not_found | The memory, link, or proposal is not visible to this caller. |
invalid_argument | Content the store refuses (reason, field); an input outside its rule (field, rule, and minimum or maximum); a change to a teammate's memory without a reason; or a field only the author may change (id, field). |
payload_too_large | Content past the store's limits (limit, maximum, field). |
quota_exceeded | The organization's memory storage quota (quota_bytes, used_bytes). |
not_owner | A teammate's memory (id). Only its author changes or deletes it; where archiving is on, archive it with a reason instead. |
archived, not_archived | The memory is archived, so restore it before changing or linking it; or a restore of a memory that is not archived (id). |
version_conflict | The memory changed since it was read (expected, actual). Read it again and retry. |
proposal_conflict, proposal_capacity_exceeded, forbidden | You already have a different pending proposal of this kind, or the proposal is already resolved (proposal_id, status); too many pending proposals (limit, maximum); or a withdraw by someone other than the proposal's author. |
link_capacity_exceeded | A new link would pass a limit (limit, maximum). |
backend_unavailable | Memory is unavailable for this call: no memory database on this environment (reason: "misconfigured", retryable: false), or the store failed. |
media__*
structuredContent.error is { code, message, retryable, status? }:
retryable says whether the same call may succeed later, and status is
present only when an upstream answered with it.
| Code | Meaning |
|---|---|
insufficient_balance | The wallet cannot cover the model's estimated hold. Top up or pick a cheaper model. |
billing_authorization_failed | The credit hold could not be recorded (retryable says whether to try again). |
billing_settlement_failed | media__understand, media__transcribe: the answer was produced but could not be settled, so it is withheld; retryable. |
key_spend_limit_exceeded, org_suspended, no_active_org | As above, caught by media's own pre-flight. |
pricing_unavailable | The model's rate cannot be established right now (retryable), or media generation is not configured on this environment (retryable: false). |
unknown_model, unsupported_model | Not a valid model id, or outside the image / video / audio catalog. |
catalog_unavailable | Model search, lookup, or schema could not be fetched (retryable says whether to try again). |
invalid_params | input fails the model's own schema. |
invalid_file_input | A file input could not be opened — the text says why (not public, no Content-Length, an expired link, an unknown handle). |
generation_failed | The generation was refused or failed upstream; the text carries the upstream's reason when it gave one. Nothing was charged. |
empty_output | The job finished without an extractable file, or the model returned no answer. Nothing was charged. |
generation_canceled, generation_expired | The job was canceled, or passed its deadline. Nothing was charged. |
job_not_found, job_not_running | No such job in this organization; or a cancel on a job that is no longer running. |
job_ledger_failed | The job ledger is unavailable; nothing was charged. Retry. |
invalid_media_url, mime_type_required, media_too_large, unsupported_media_type, invalid_media_window | media__understand input problems: the media URL, its type, its size, or the requested time window. |
file_not_found, upload_processing, upload_unprocessable | The Drive file is unknown, expired, or not visible to you; still being prepared (retryable, nothing charged); or rejected by the analysis backend. |
upload_quota_exceeded, upload_capacity_exhausted, quota_unavailable | drive__create_upload, and media__understand when it copies a URL: the organization's tmp/ space, the platform's upload capacity, or the quota ledger being unavailable. |
understanding_failed, rate_limited, content_blocked, incomplete_output, invalid_usage_metadata, internal_error | media__understand: the model failed (status), rate-limited, blocked the request, returned a cut-off answer, reported no usable usage, or was unavailable. |
transcription_failed | media__transcribe: the recording was refused (too long, undecodable, too short); the text carries the reason. Nothing was charged. |
upstream_unavailable | media__transcribe, media__list_voices, and a media__generate call whose voice could not be checked: the service could not answer right now; retryable. Nothing was charged. |
not_configured | Media is not configured on this environment. |
cancelled | The call was cancelled. |
web__* and social__*
| Code | Meaning |
|---|---|
invalid_input | Arguments refused before any request left CoreSpeed (field and reason from web__scrape, issues from the other tools). |
upstream_error | The search or data supplier refused the request (status, and request_id and retry_after_seconds when sent; social may add upstream_code). |
rate_limited | The supplier rate-limited the call (status, and retry_after_seconds when sent). |
upstream_unreachable | The supplier could not be reached, or timed out. |
upstream_response_invalid | The supplier answered with something unreadable (status). |
cancelled | The call was cancelled. |
no_content | web__scrape: the page had no readable text. |
timeout | A live-collection tool (Facebook, Threads, Google Search and Maps, Airbnb, TripAdvisor, Amazon, Zillow) reached timeout_seconds before returning any result. Nothing was charged; raise timeout_seconds or narrow the request. |
collection_failed | A live-collection tool's run failed upstream — often an id, URL, or name that does not exist. Nothing was charged. |
drive__*
structuredContent.error is { code, message, retryable? }. Drive calls are
never charged, so nothing is refunded on a failure.
| Code | Meaning |
|---|---|
invalid_path | The path breaks the Drive's naming rules; the text says which rule. |
file_not_found | No file at that path, file id or version id that you can see. |
path_taken | drive__move: the destination already names a file. |
file_too_large | A file under tmp/ is over the per-file limit; put it on a kept path instead. |
drive_quota_exceeded | The write would pass the plan's kept-bytes ceiling (drive__usage shows the numbers). |
upload_quota_exceeded, upload_capacity_exhausted, quota_unavailable | The organization's tmp/ pool or the platform's is full, or the ledger that reserves it is unavailable (retryable); uploads expire on their own. |
put_raced, precondition_failed | Another write created or changed the path at the same moment; retry the put. |
storage_error | Storage could not be reached (retryable), or the file's storage is not reachable from this deployment. |
drive_unavailable | The Drive index is unavailable (retryable), or sharing by link or publicly is not configured on this deployment. |
content_length_mismatch | drive__put from a URL: the origin sent fewer or more bytes than its Content-Length. |
Manage tools
| Code | Meaning |
|---|---|
api_key_cannot_mint, member_principal_required | A key on a minting tool; an agent principal on a member's own act (above). |
no_active_org, platform_db_unavailable | As above. |
invalid_arguments | An argument the tool refuses (field). |
api_key_not_found, invalid_spend_limit, agent_self_escalation, org_wallet_missing | manage__keys_*: no such key in scope; a cap that is not above zero; an agent key changing key settings; no wallet for the organization. |
session_client_id_missing | manage__keys_create, manage__agents_key_create: the session token has no client_id claim; sign in again from a CoreSpeed client. |
ceiling_exceeded, unknown_permission, agent_key_permissions | manage__keys_create, manage__agents_key_create: a slug the caller's token cannot hand on (missing; a token from an MCP sign-in hands on none); a slug that is not a permission (unknown); any slug on an agent's key. |
agent_not_found, agent_not_active, agent_already_retired, agent_not_manageable, agent_owner_not_member, insufficient_role | manage__agents_*: no such agent; not active (suspended or retired), so it cannot get a key; retired; the caller is neither its owner nor a holder of agents:manage; the new owner is not a member; giving an agent away needs agents:transfer. |
account_not_found, alias_taken, alias_blank, alias_reserved, alias_ambiguous, account_removal_forbidden | manage__accounts_*: no such alias (inside an environment: none of the environment's accounts); the new alias is taken, empty, or reserved for the connector's organization integration; accounts_remove matched more than one account; the caller may not remove a shared account. |
environment_not_found, environment_name_taken, environment_in_use, connection_not_reachable, unknown_tools, tools_empty, agent_not_manageable | manage__environments_* and the key tools' environment: none you may manage by that id or name; the owner already has one by that name; active keys are bound to it (keys); an entry names an account the owner cannot use (connection_ids); a tool list names tools the connector does not publish, or none; only the agent's owner or a holder of agents:manage manages its environments. |
environment_active, environment_mismatch | The session runs in an environment: environments cannot be edited, an agent's key minted, nor a remote MCP server added, refreshed or removed from inside one; a key minted here is bound to this environment and cannot name another. |
invalid_grantee, grantee_not_in_org, unknown_tools, tools_empty, not_shareable, ambiguous_account, forbidden, grant_not_found | manage__accounts_share and manage__accounts_unshare: the grantee is not a user_…, agent_…, or org_… id, or not in this organization; tools names tools the connector does not publish (unknown), or none; this connector's personal accounts stay private; the alias names both a private and a shared account; only the owner (or, for a shared account, its creator or a holder of connections:org) may change its shares; the account is not shared with that grantee. |
connector_not_found, connect_link_unsupported, connector_not_shareable, agent_owner_missing | manage__connectors_connect: no connector by that id can be connected here (also from manage__connectors_wait); the id names a custom MCP server your organization added (connect it in the dashboard); an agent key asked for Slack or Linear, whose personal accounts are never shared (it uses the organization integration); the agent key's agent has no owner to open the link. Inside an environment manage__connectors_connect and manage__connectors_wait answer environment_active. |
identity_provider_unavailable, switch_org_unsupported | manage__switch_org: the identity provider did not answer, so nothing changed; or the session has no browser-OAuth client to re-authorize (an API key's organization is fixed by the key). |
admin_required | A manage__remote_* write without connections:org (permission). |
slug_taken, invalid_url, oauth_discovery_failed, cooldown, snapshot_failed, kv_unavailable, … | manage__remote_*: the same codes as the /connectors/org routes above, as tool codes. An unknown slug is not_found, and cooldown carries retry_after_seconds. |
feedback_rate_limited | manage__send_feedback: the organization sent its 50 items for the rolling day (limit). Tell your user instead of retrying. |
approval_not_found | manage__approval_wait: no approval with that id for this caller. |
approval_coordinator_unreachable | The wait lost contact with the approval; call it again with the same id. A call that already ran is never run twice. |
approval_arguments_unreadable | The approved call's frozen arguments could not be read, so it was not run. |
approved_tool_unresolvable | The approved tool is no longer available to this caller, so it was not run. |
approval_settings_unreadable, approval_surface_unavailable | The approved call was not run because CoreSpeed could not read the settings it must run under, or rebuild the caller's tools. The approval is used up; request the call again once CoreSpeed recovers. |
A pending, denied, or expired card — or one an earlier wait already ran —
comes back as its receipt, with the state in _meta["io.corespeed/approval"].
Remote MCP servers
An org-registered server's own isError results are forwarded verbatim. When
the call fails on CoreSpeed's side, an org__<slug>__* tool answers:
| Code | Meaning |
|---|---|
not_connected, needs_reauth, refresh_failed, unauthorized | The caller's authorization for this server is missing, dead, could not be renewed (status), or was refused. Reauthorize in the dashboard; for a server registered with a static token, re-add it. |
oauth_client_missing, oauth_client_unreadable, credential_undecryptable | The registration's OAuth client is missing or unreadable, so a holder of connections:org re-registers the server; or the stored credential is unusable, so reconnect it. |
invalid_url, not_https, has_credentials, credential_in_query, has_fragment, ip_literal, loopback_or_local, self_host | The server's URL is refused by CoreSpeed's URL guard. |
redirect_refused, response_too_large, too_many_tools, protocol_error | The server redirected, answered past the size limit, listed too many tools, or spoke something that is not MCP. |
timeout, cancelled | The call timed out or was cancelled; its upstream outcome is unconfirmed. |
upstream_error | The server refused the request (status for an HTTP refusal), answered with a JSON-RPC error, or could not be reached. When unreachable, a write may have landed. |
platform_db_unavailable | As above. |
Codes in the activity trail only
Some results reach the agent as a receipt or as an upstream's own result, with
no structuredContent.error. The organization's
activity trail still records a code for them:
approval_pending and denied_by_policy (the approval gate's receipts);
approval_denied, approval_pending, approval_expired,
approval_already_taken and approved_call_failed (manage__approval_wait
answering a closed card, or the approved call's own failure); upstream_error
(a vendor's or org server's isError result, forwarded verbatim);
component_root_conflict (Webflow's result, forwarded with advice); and
approved_tool_unavailable (the replay of an approved call whose tool is gone).
Recovery at a glance
| Symptom | First move |
|---|---|
401 on every call | Check the header form, then whether the key was revoked. |
429 in bursts | Back off for Retry-After. The window follows the credential, one or the other: a session call is limited per user, an API-key call per key. A runaway key is throttled on its own without consuming its owner's session window. |
402 on billable operations only | Top up. Discovery still works, so the surface is intact. |
403 org_suspended | Support. No client-side fix exists. |
403 api_key_cannot_mint | Mint the key from the dashboard or a signed-in client; a key does not mint keys. |
403 member_principal_required | That act is a member's (create an agent, shape an environment, the /me user actions); use a member's credential. |
404 on a tool call URL | You are calling a retired per-connector URL. Use POST /mcp. |
500 or tool code internal | Retry once with backoff; quote the request_id to support. |
Tool missing from tools/list | Capability disabled, or the account is not connected for this caller. |
Tool code needs_reauth | Reauthorize the account in the dashboard. |
Tool code ambiguous_account | Pass account with one of error.aliases. |