Errors & limits

Every failed request returns a structured error. The hosted surfaces use exactly three envelope shapes — tool errors, MCP protocol errors, and account-surface errors — and this page lists every code, when it fires, whether retrying helps, and how to fix it. Tool calls run at https://mcp.agentastrology.com — REST at POST /v1/tools/{tool}, MCP at /mcp. Key management runs at https://api.agentastrology.com.

1. The three envelopes

Tool errors — REST bodies and MCP tool results share this shape:

{
  "error": {
    "code": "invalid_input",
    "message": "Invalid input: expected object, received undefined at birthData"
  }
}

code is stable and switchable; message is human-readable — include it in bug reports. Some codes add fields (method, requiredTier, resetAt) — shown per code below. On MCP, this object sits under structuredContent.error of a result with isError: true; on REST it is the response body and the HTTP status carries the class.

MCP protocol errors — JSON-RPC error objects ({"jsonrpc":"2.0","id":…,"error":{"code":-32602,"message":"…"}}) for transport-level failures: malformed JSON, wrong headers, unknown tool name, malformed call params. Covered in §5.

Account-surface errors — a flat shape {"error":"unauthorized","message":"Sign in required"} (note: error is the code string itself, not an object). Covered in §7.

2. Master table — every tool-surface code

CodeHTTP (REST)Fires whenRetryable?What to do
invalid_input400A field is missing, mistyped, or out of range; the method value isn't one of the tool's methods; the request body isn't a JSON objectNoFix the payload — the message names the first bad field and its path
invalid_birth_data400Compute rejects the birth data past schema validation (latitude/longitude/unknown-time constraint messages)NoFix the named birth-data field
unknown_tool404The REST slug doesn't existNoCheck the slug against GET /v1/tools
missing_api_key401A REST tool call carries no credentialsNoSend Authorization: Bearer <key> or x-api-key: <key>
invalid_api_key401The key is unknown or revokedNoCheck the key on your account page; create a new one if revoked
tier_denied403The method is paid-tier and the key's tier doesn't include itNoCall a free method, or upgrade the key when paid tiers launch
rate_limited429The key's monthly call quota is exhaustedYes — after resetAtWait for the window reset (§6); retrying earlier returns the same 429
method_not_yet_implemented501The method is announced but not shipped (none on the current surface)NoWait for the release; the message names the method
sweph_failure500The ephemeris cannot cover the request — most commonly a chart date before ~675 AD, which is outside Chiron's range (§8)NoMove the date into the supported range
geocode_failure500A place name cannot be resolved to coordinatesOnceRetry once; if it persists, pass a more specific place or explicit coordinates
internal_error500Anything the service couldn't classify, including dates several millennia out (§8)OnceRetry once; if it persists, report the full message
auth_unavailable503The auth backend is temporarily not accepting checksYesRetry with backoff
auth_upstream_error502The auth backend was unreachableYesRetry with backoff; if persistent, check status page

invalid_input and invalid_birth_data are almost always caller bugs — a string timezone instead of a number, birthData nested into a flat tool like astro_moment, or a method that belongs to a different tool. Fix the payload, not the service.

3. Worked failure payloads

Missing required field

astro_chart called with {"method": "natal"} and no birthData:

{
  "error": {
    "code": "invalid_input",
    "message": "Invalid input: expected object, received undefined at birthData"
  }
}

The message is built from the first schema issue — its text plus the path (birthData). The underlying issue the validator raised for this call, shown so you know what the parts mean:

{
  "expected": "object",
  "code": "invalid_type",
  "path": ["birthData"],
  "message": "Invalid input: expected object, received undefined"
}

Value out of range

birthData.year: 9999 — years run −4000..4000:

{
  "error": {
    "code": "invalid_input",
    "message": "Too big: expected number to be <=4000 at birthData.year"
  }
}

Method that isn't on the tool

Two shapes depending on where it is caught. With a key (HTTP surfaces), the gate answers and names the tool:

{
  "error": {
    "code": "invalid_input",
    "message": "astro_chart has no method 'nope'",
    "method": "nope",
    "requiredTier": null
  }
}

Without the gate (local stdio), schema validation answers instead:

{
  "error": {
    "code": "invalid_input",
    "message": "Invalid input at method"
  }
}

Missing key

curl -sS -X POST https://mcp.agentastrology.com/v1/tools/astro_chart \
  -H "Content-Type: application/json" \
  -d '{"method":"natal"}'
{
  "error": {
    "code": "missing_api_key",
    "message": "Provide Authorization: Bearer <key> or x-api-key"
  }
}

Unknown or revoked key (HTTP 401)

{
  "error": {
    "code": "invalid_api_key",
    "message": "Unknown or revoked API key"
  }
}

Tier-gated method on a free key (HTTP 403)

{
  "error": {
    "code": "tier_denied",
    "message": "astro_aspects.between-charts requires the paid tier",
    "method": "between-charts",
    "requiredTier": "paid"
  }
}

Quota exhausted (HTTP 429)

{
  "error": {
    "code": "rate_limited",
    "message": "Monthly quota exhausted",
    "resetAt": "2026-09-01T00:00:00.000Z"
  }
}

resetAt is ISO 8601 — the start of the next UTC calendar month. There is no rate-limit response header; read the reset time from the body.

Not-yet-implemented method (HTTP 501)

No method on the current surface returns it — if you ever see it, the method is announced but not shipped:

{
  "error": {
    "code": "method_not_yet_implemented",
    "message": "Method astro_returns.saturn is not yet implemented (Paid tier, coming soon).",
    "method": "astro_returns.saturn"
  }
}

Ephemeris limit — Chiron range (HTTP 500)

Natal chart for year 600:

{
  "error": {
    "code": "sweph_failure",
    "message": "calc failed for planet 15: Chiron's ephemeris is restricted to JD 1967601.5 - JD 3419437.5"
  }
}

Ephemeris limit — date too remote (HTTP 500)

For year −4000:

{
  "error": {
    "code": "internal_error",
    "message": "calc failed for planet 0: SwissEph file 'seplm42.se1' not found in PATH <ephemeris dir>"
  }
}

Non-object REST body (HTTP 400)

Body [] — returned before authentication, so you can see it without a key:

{
  "error": {
    "code": "invalid_input",
    "message": "request body must be a JSON object"
  }
}

4. MCP results and protocol errors

Tool-level failures — failure is a normal result object with isError: true and the envelope under structuredContent.error. Check isError before parsing anything else — it is the only reliable success/failure signal. Prefer structuredContent over content[0].text when your client surfaces it; the text block is the same JSON as a string. Example:

{
  "isError": true,
  "structuredContent": {
    "error": {
      "code": "invalid_input",
      "message": "Invalid input: expected object, received undefined at birthData"
    }
  },
  "content": [
    {
      "type": "text",
      "text": "{\"error\":{\"code\":\"invalid_input\",\"message\":\"Invalid input: expected object, received undefined at birthData\"}}"
    }
  ]
}

Protocol errors — JSON-RPC error objects for transport-level failures:

JSON-RPC codeHTTPFires whenWhat to do
-32700400The POST body isn't valid JSONFix the JSON
-32000406Missing Accept pair — the endpoint requires both application/json and text/event-streamSend Accept: application/json, text/event-stream
-32601200Unknown JSON-RPC methodUse the MCP methods your client library sends
-32602200tools/call names a tool that doesn't existCheck the name against tools/list
-32603200tools/call params are malformed (e.g. name missing)Fix the call params; the message quotes the failed fields

Tool not found (note: in-protocol errors ride HTTP 200 — always check the body, not just the status):

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "MCP error -32602: Tool astro_nope not found"
  }
}

Malformed JSON body:

{
  "jsonrpc": "2.0",
  "error": { "code": -32700, "message": "Parse error: Invalid JSON" },
  "id": null
}

Two facts to keep in mind. First, invalid tool ARGUMENTS are never protocol errors — they come back as isError: true results with invalid_input so your agent can read and fix them. Second, auth on /mcp is checked per HTTP request before the protocol runs, so auth failures arrive as plain JSON HTTP errors (§3 codes), not JSON-RPC errors.

5. Rate limits

  • Free tier: 500 calls per month. Paid tier: 50,000 calls per month. Enforced per key over the UTC calendar month; the window resets at 00:00 UTC on the first of the next month (that instant is the 429 body's resetAt).
  • All keys are currently issued at paid tier with full access during the beta, so 50,000 is the number to plan against today.
  • Every authenticated call draws one unit: each REST tool call, and each HTTP POST to /mcp — including initialize and tools/list.
  • GET /v1/tools, GET /v1/openapi.json, and the health endpoint are unauthenticated and never count.
  • Retrying while limited returns the same 429 and does not push the reset later.
  • There is no rate-limit header on responses; the reset time lives only in the 429 body (error.resetAt, ISO 8601).

6. Account-surface errors (api.agentastrology.com)

Key management (/keys, /usage) is session-authenticated — sign in on the website; the dashboard drives these. Its envelope is flat — error IS the code string:

{
  "error": "unauthorized",
  "message": "Sign in required"
}
CodeHTTPFires whenWhat to do
unauthorized401No valid sessionSign in at the website and retry from the account page
invalid_input400Body isn't valid JSON, or name isn't a string of 1..64 charsFix the request body
not_found404Deleting a key that doesn't exist (or isn't yours)List keys first; it may already be revoked
endpoint_moved410Calling the retired /rpc/* or /chart/* pathsUse the current REST/MCP endpoints on mcp.agentastrology.com

7. Compute limits and silent fallbacks

  • Chart dates accept years −4000..4000; outside that, schema validation answers with invalid_input naming year (§3, "Value out of range").
  • Precision ephemeris data covers roughly 1200–2999 AD. Outside it, main bodies fall back to a built-in lower-precision model, but Chiron has a hard range of JD 1967601.5–3419437.5 (about 675 AD to 4650 AD) — and default charts include Chiron, so charts before ~675 AD fail with the sweph_failure shown under "Ephemeris limit — Chiron range". Dates several millennia out exceed the fallback model too and fail with the internal_error naming a missing ephemeris file.
  • Polar latitudes are NOT an error: inside the polar circles, where Placidus/Koch-family cusps are undefined, the service computes Porphyry cusps instead and returns success — the same behavior as the major reference software. The chart's summary.houseSystem label still names the system you asked for, so check latitudes above ~66° if cusps look evenly trisected.