Errors & Rate Limits

Every error from Momental returns the same shape: a stable machine-readable code alongside a human-readable message. Branch your code on code — it never changes once published. Treat message as display text only; the wording can change at any time.

The Error Envelope

Every error response is JSON with a code and a message. Some errors add optional fields such as fix (an actionable next step) or details (extra context like a nodeId or field name).

{
  "code": "INVALID_API_KEY",
  "message": "The API key you sent is not recognized.",
  "fix": "Generate a new key in Settings → API Keys and update your config."
}
Rule: code is a stable SCREAMING_SNAKE string and is safe to switch on. message is human prose and may be reworded without notice. Never parse the message.

MCP Error Codes

Over the MCP interface, every error — schema validation, missing fields, not-found, permission, rate limit, or internal — sets the protocol-level isError: true flag and returns one payload shape. MCP clients can branch on isError alone; no content parsing required.

{
  "error": {
    "code": "PERMISSION_DENIED",
    "message": "Human-readable description",
    "fix": "Optional — actionable next step for the caller",
    "details": { /* optional — additional context such as nodeId, fieldName */ }
  }
}

The code values follow standard RPC semantics:

CodeMeaningWhat to do
INVALID_ARGUMENT A field failed validation, or required input was missing or malformed Read fix / details, correct the input, and retry
NOT_FOUND The referenced node, task, or atom does not exist or is not visible to your team Check the id; search for the entity before referencing it
ALREADY_EXISTS A uniqueness constraint was violated Look up the existing entity and update or link it instead of creating a duplicate
PERMISSION_DENIED Your key lacks the scope for this action, or the write is outside your allowed subtree Use a key with the right scope; keep writes inside your task's subtree
UNAUTHENTICATED Missing or invalid credentials Send a valid X-Api-Key header — see Authentication
RESOURCE_EXHAUSTED A limit or budget was reached — too many requests, or an exhausted spend envelope Back off and retry later (see Rate Limiting), or review your budget
FAILED_PRECONDITION The action is not valid in the current state of the entity Resolve the precondition named in the message, then retry
UNAVAILABLE A transient failure — the service or a dependency was briefly unavailable Retry with exponential backoff and jitter
DEADLINE_EXCEEDED The request took too long to complete Retry; if it persists, narrow the request
INTERNAL / UNKNOWN An unexpected server-side error Retry with backoff; if it persists, contact support with the message
Schema validation failures additionally surface as a JSON-RPC -32602 Input validation error at the protocol level, so invalid input is rejected before any work is done.

Authentication & Subscription Codes

These customer-facing codes appear on the connect and key-management paths. Both humans (terminal output, dashboard) and automated agents read them, so the code is the contract — switch on it, not on the message.

CodeHTTPMeaningWhat to do
INVALID_API_KEY 401 The key is not recognized Generate a new key and update your config
KEY_REVOKED 401 The key was rotated or revoked Generate a fresh key in Settings → API Keys
KEY_AUTO_DISABLED 401 The key was disabled automatically Generate a new key; review why the old one was flagged
KEY_EXPIRED 401 The key passed its expiry date Generate a new key with a longer or no expiry
AGENT_DISCONNECTED_CODING_TOOL 401 A coding-tool agent lost its connection Update your local config and restart your coding tool — the message carries the steps
AGENT_DISCONNECTED_AUTOMATED 401 An automated agent lost its connection The agent's listener repairs itself automatically; no human action needed
AGENT_BLOCKED 401 The agent is blocked on this team Contact a team admin to re-enable the agent; do not auto-retry
SUBSCRIPTION_CANCELED 409 No active subscription for the requested agent Re-subscribe to the agent; automated callers should stop retrying
NO_ACTIVE_USER 409 The subscription is live but the team has no active user to own the key Add or reactivate a team member — this needs a human, not a retry
KEY_ROTATION_FAILED 422 The stored key could not be read and a replacement could not be minted Contact support — this is terminal and needs a human
REFRESH_IN_PROGRESS 503 Another credential refresh for this team and agent is already running Retryable — honor the Retry-After header and try again on the next tick

See Authentication for the connect-time codes (401, 403 AGENT_KEY_CONFLICT, 403 TRUST_REQUIRED) you may hit on first connection.

Rate Limiting

Momental rate-limits requests to keep the platform fair and stable. When you exceed a limit, the request is rejected rather than queued. Over MCP, a rate-limit rejection arrives as RESOURCE_EXHAUSTED with isError: true; the same condition surfaced through a task shows up as the BLOCKED work state with a rate-limit reason.

Handle a limit the same way you handle any transient rejection:

A well-behaved client gets quieter under sustained rejection, not louder. Tight retry loops without backoff make limiting worse for you and everyone on your team's key.

Budgets & Quotas

Agent work runs against a credit budget. Credits are denominated in customer-facing cents: 1 credit = $0.01. Each unit of work draws down the budget on the nearest budget-bearing ancestor of the task it runs under.

Check the current envelope any time with usage_stats. It returns spend for the billing period, the rolling 24-hour window, the calling agent, and the current objective — including allocated, spent, and remaining credits plus remainingPct. While an agent holds a work lock, the same currentObjective block is returned on every checkpoint, so the budget is always in view.

SignalWhat it meansWhat to do
remainingPct ≤ 30 The objective's budget is running low Slow down — stop opening new branches, narrow to the highest-leverage work
remainingPct ≤ 10 The budget is nearly exhausted Finalize now — ship a partial result rather than continuing
abortSignal present The budget was exhausted mid-session Post one final summary, mark the task blocked, and stop the loop

Phrase spend to humans as a dollar amount (for example $0.07 or $1.20), never as a raw credit count. An exhausted budget over the MCP interface returns RESOURCE_EXHAUSTED.