Prowl ← Back to home
LIMITS & ERRORS

Rate limits & error handling

Every limit, every error code, and how to back off cleanly

Prowl throttles the MCP endpoint at two layers: a pre-auth cap of 300 requests/min per client IP (MCP_PREAUTH_IP_LIMIT_PER_MIN) applied before your key is even validated, and a 120 requests/min per API key cap (MCP_RATE_LIMIT_PER_MIN) after auth. Both use a 60-second sliding window and return HTTP 429 with JSON-RPC error code -32002. Auth failures return 401 / -32001, IP-allowlist rejections return 403 / -32003, and anything unexpected returns -32603. Per-tool problems come back as an Error: string inside a normal tool result, not as a protocol error.

Two things error out in two different ways

It helps to keep these separate:

  • Transport / auth errors — a bad key, a rate-limit breach, or a blocked IP are rejected by the MCP middleware before your call runs. You get a real JSON-RPC 2.0 error body with the codes in the table below.
  • Tool-call errors — insufficient wallet balance, a key scope denial, a spend-cap hit, an oversized payload, or an unknown tool name are returned as a successful tool response whose text starts with Error:. The JSON-RPC call succeeds; the content tells you what went wrong.

So your client should check both the JSON-RPC error field and whether a tool result string begins with Error:.

Rate-limit table

SurfaceLimit (default)WindowScopeResponse
MCP endpoint, pre-auth300 / min60s slidingper client IP429, JSON-RPC -32002
MCP endpoint, per key120 / min60s slidingper API key429, JSON-RPC -32002
Login1060sper IP429 + Retry-After
Register53600sper IP429 + Retry-After
Billing (checkout, top-up, verify, change, cancel)560sper user429 + Retry-After
Schedule webhook trigger660sper webhook token429 + Retry-After
Admin write endpoints3060sper user429 + Retry-After

All windows are sliding buckets and are shared across server workers when Redis is configured. Every MCP and web limiter is env-tunable except the billing (5) and admin-write (30) limits, which are hardcoded.

Handling a 429 (backoff guidance)

How you back off depends on which layer threw the 429:

  • Web REST 429s (login, register, billing, webhook, admin, OAuth, key-cap) always include a Retry-After response header. Its value is the window upper bound in whole seconds. Honor it: wait that many seconds before retrying.
  • MCP transport 429s (-32002 from the pre-auth IP cap or the per-key cap) do not carry a Retry-After header. Use exponential backoff with jitter — start around 1s, double each retry, cap the delay, and add randomness so retries don't synchronize. The window is 60 seconds, so a breach clears within a minute.

Best practice: keep steady-state traffic under 120 requests/min per key and 300 requests/min per IP, serialize bursts, and treat any 429 as a signal to slow down.

JSON-RPC error codes (transport / auth layer)

JSON-RPC codeHTTPMeaningExample message
-32001401Auth failure"Missing or invalid Authorization header. Use: Bearer prowl_<your_key>" / "Invalid or revoked API key."
-32002429Rate limit exceeded"Rate limit exceeded for this API key. Max 120 requests/min. Slow down and retry."
-32003403IP not allowlisted"API key is not allowed from this IP address."
-32603500 / 503Internal / fallback errorgeneric internal error

Every 401 also returns a WWW-Authenticate: Bearer realm="prowl-mcp", resource_metadata="<PRM URL>" header (RFC 9728) so OAuth-capable clients can auto-discover the authorization server.

Common tool-call errors

These arrive as the text of a normal tool result (prefix Error:), so read the string, not the JSON-RPC error field:

SituationWhat you get back
Insufficient wallet balance"Error: Insufficient wallet balance. Need $X available, have $Y. Top up credits in MCP Home or subscribe at prowl.chat."
Key scope denied"Error: API key is not allowed to call tools in category '<category>'. Tool '<tool_name>' was blocked by key scope policy."
Per-key spend cap hit"Error: API key spend limit reached (<reason>). Top up your wallet or use a key with a higher limit."
Params too large (prowl_call_tool)"Error: params too large (<n> bytes); max 65536 bytes."
Tool not found"Error: Tool '<tool_name>' not found. Use prowl_list_tools to see available tools."
Tool not found (prowl_tool_info)"Error: Tool '<tool_name>' not found. Available tools (first 20): … Use prowl_list_tools to see the full catalog."
Internal error"Error: Analysis failed due to an internal error. Please retry. (ref: <id>)" — quote the ref: id to support
Billing DB outage, fail-closed"Error: Billing is temporarily unavailable. Please retry in a moment."

Billing fails closed by default: during a database outage Prowl refuses paid work rather than handing out free runs. When a tool succeeds but the charge can't be fully collected, the result still returns your data plus a warning, and you are not double-charged.

Debug after the fact with prowl_get_error_feed

For a retrospective view of what failed on your account, call prowl_get_error_feed. It is read-only, scoped to your own account, and returns recent failed tool calls, billing events, and actions.

  • hours — lookback window, default 24, max 720.
  • limit — max rows, default 50, max 200.
  • source — tool_error, action, tool_invocation, or billing_outbox.
  • error_class — network, server, auth, rate_limit, timeout, plan_denied, client, or unknown.
  • severity — alert, warn, or info; also filter by tool_name.

Frequently asked questions

What are Prowl's default MCP rate limits?

300 requests per minute per client IP before authentication (MCP_PREAUTH_IP_LIMIT_PER_MIN) and 120 requests per minute per API key after authentication (MCP_RATE_LIMIT_PER_MIN). Both use a 60-second sliding window and return HTTP 429 with JSON-RPC error code -32002.

How should I handle a 429 response?

Web REST endpoints (login, register, billing, webhooks, OAuth) include a Retry-After header in whole seconds - wait that long, then retry. The MCP transport 429 has no Retry-After header, so use exponential backoff with jitter starting around 1 second; the 60-second window clears the breach within a minute either way.

What do the JSON-RPC error codes mean?

-32001 is an auth failure (HTTP 401), -32002 is a rate-limit breach (HTTP 429), -32003 is an IP-allowlist rejection (HTTP 403), and -32603 is an internal error (HTTP 500/503). Auth and IP errors are thrown by the middleware before your tool runs.

Why did my tool call return an 'Error:' string instead of failing?

Per-tool problems - insufficient wallet balance, key scope denial, spend-cap hit, oversized params, or an unknown tool name - are returned as the text of a successful tool result that starts with 'Error:'. Only transport and auth problems come back as real JSON-RPC error codes.

How do I see what failed on my account?

Call prowl_get_error_feed. It is read-only and scoped to your account, returning recent failed tool calls, billing events, and actions. Filter by hours (default 24, max 720), source, error_class, severity, or tool_name, and quote any 'ref:' id when contacting support.

Related

  • What to expect from a report run→
  • Billing & Wallet Top-Ups→
  • Scheduling & webhooks→
Start with $5 free credit →
Prowl
Getting started Docs Use cases Contact Privacy Terms
© 2026 Prowl. Market intelligence.