Skip to main content

Errors

Applies toEDITED MCPQuery APIJobs API

EDITED's surfaces report failures in two different shapes. MCP answers over JSON-RPC, so a failure can hide in one of three layers — the HTTP status, the JSON-RPC envelope, or the tool payload. The REST APIs (Query and Jobs) report everything through plain HTTP status codes, the way a REST client expects. Read the section for the surface you're on.

MCP​

EDITED MCP

Failures surface at three layers: the HTTP status (did the request reach the server and authenticate?), the JSON-RPC envelope (did the call itself succeed?), and the tool payload (did the tool run and then refuse?). Check all three — the third is the one a shared response handler usually misses.

HTTP status codes​

StatusMeaning
200The request was processed — but the body may still carry a JSON-RPC error (below)
400The body wasn't parseable JSON, wasn't a JSON-RPC envelope at all, or was a batch array over the 64-envelope cap — the error code is -32700 or -32600
401Missing access key, or the key isn't enabled for MCP — see Authentication & access
5xxTransient server-side failure — safe to retry with backoff

JSON-RPC errors​

A failed call returns an error envelope instead of a result:

{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32602, "message": "Invalid request parameters" }
}
CodeMeaningUsual cause
-32700Parse errorThe body isn't valid JSON — arrives at HTTP 400
-32600Invalid requestThe envelope wasn't usable. At HTTP 400, the body is valid JSON but not a JSON-RPC object or batch array — or a batch over the 64-envelope cap. At HTTP 200, a tools/call arrived with no usable name — either omitted outright, or because params was sent positionally and a non-object params is read as empty. Not caused by a missing MCP-Protocol-Version header — see Versioning
-32601Method not foundWrong method name — e.g. tool/call for tools/call
-32602Invalid paramsMalformed params: a non-object arguments, or a tool name whose namespace prefix we don't serve (mdmcp-search_brands, not search_brands) — check the Reference. Arguments that merely don't match a tool's input schema do not land here; that call succeeds at HTTP 200 and carries the refusal in its payload — see below
-32603Internal errorServer-side failure while executing — safe to retry
-32002Resource not foundUnknown resource URI — check the Reference for the ones this server publishes
-32003Not authorisedYour key is valid, but your subscription doesn't include that backend — see below
-32004Backend unavailableThat backend is being shed after repeated failures. Back off substantially longer than for -32603 — retrying quickly only extends it
-32099Rate limitedToo many requests — see Rate limits

Most tool refusals arrive in the payload, not on isError​

When a tool runs and then refuses, the call succeeds at the protocol level and the refusal is in the payload — note isError is false:

{
"isError": false,
"structuredContent": {
"error": {
"code": "invalid_input",
"message": "topic: Input should be 'filter_fields', 'metrics', …",
"field": "topic"
}
}
}
codeMeaningRetry?
invalid_inputArguments refused. Often with field naming the one to change — the market-data tools set it consistently, research and messaging only sometimes.No — fix the request
not_entitledThe backend refused your subscription's access to this data.No
upstream_unavailableA dependency is failing or slow.Yes, with backoff
internalOur side is wrong: a malformed record, or a guard we can't satisfy. A retry returns the identical error, which is why it isn't worth one. Distinct from -32603 above, which is the gateway failing rather than a tool.No

A client branching only on isError reads an in-band refusal as a success, and then finds no data where it expected some. A client branching only on the payload crashes on the isError cases, where structuredContent is null. Check isError first — when it is true the text is prose, not JSON — then check the payload for error. See Concepts → Response shape for which refusals use which channel, and a ready-made unwrapper.

"Not provisioned" has three different shapes​

Worth separating, because they arrive at three different layers and only the last one is a not_entitled payload:

What is wrongHow it arrives
The key is unrecognised, or not enabled for MCPHTTP 401 — nothing reaches a tool
The key is valid, but your subscription does not include that backendJSON-RPC -32003 at HTTP 200
The key reaches the backend, which refuses the specific dataIn-band not_entitled, isError: false

Empty results aren't errors​

A search that returns an empty list succeeded — no match cleared the relevance threshold. Rephrase the query, make it more specific, or batch several phrasings in one call (see Concepts → Tools).

This is distinct from a refusal: an empty answer arrives on the result branch with no error at all.

Retrying​

Every EDITED MCP tool is a read-only search with no side-effects, so retries are always safe. Retry 5xx, -32603 and -32099 with exponential backoff; on -32004 back off substantially longer, since that backend is already being shed and quick retries prolong it. Don't retry 401, -32700, -32600 or -32602 — those need a fix (key, request shape, or tool-name prefix), not patience.

An isError: true result is worth exactly one retry. It carries no code to branch on, and the channel mixes two unlike things: a genuine bug, and a transient failure raised below the tool's own error handling. Retry once with backoff; if it comes back identically, treat it as a bug and report it.

Among the in-band codes, only upstream_unavailable is worth retrying. internal is not — it means a retry returns the same error, not that we are having a bad minute.

REST APIs​

Query API Jobs API

The Query and Jobs APIs report success and failure through the HTTP status code — there's no JSON-RPC envelope, and every error carries a message body with more detail. As a rule of thumb a 4xx is your request to fix and a 5xx is ours — but the line isn't clean: some request and access problems surface as a 500, so read the body, not just the status.

REST status codes​

StatusMeaning
200Success — read the result from the body.
204No Content — a Jobs cancel or resume returns 204 with an empty body. (A submit returns 200 with a job_id.)
400Bad request — malformed syntax or unparseable body. The message body says more.
401Unauthorised — the access key is missing. See Authentication & access.
403Forbidden — the key isn't permitted for what you're calling (unknown, or a valid key without access to this surface or data), or the request used plain http (EDITED accepts https only).
404Not found — an unknown job, option, or resource.
409 Jobs APIThe job can't change state: you can only cancel a processing, pending, or queued job, and only resume a canceled or errored one.
422 Jobs APIValidation error — the request was well-formed JSON but invalid (e.g. a bad date range or filter). The message body says which field.
429Too many requests — you've hit a rate limit. Wait, then retry.
5xxServer-side failure — usually transient (retry with backoff). But some request problems also come back as 500; read the body, and see the note under Retrying REST calls.

Retrying REST calls​

The read endpoints (Query, and the Jobs read/poll endpoints) are safe to retry.

  • 429 and 5xx — usually transient; back off and retry with exponential backoff. 429 responses don't carry a Retry-After; wait a little longer each time, and reduce how many requests you fire in a burst. Cap your retries: a 500 that returns the same error every time is usually a request or access problem in disguise (see the note below), not a blip.
  • 504 on a large option_history request — the request timed out. Split it into smaller date ranges, or paginate, rather than retrying the same call.
  • 400, 401, 403, 422, 409 — don't retry; each needs a fix (the request shape, the key, https, the body, or the job's state), not patience.
Not every 500 is transient

A 500 isn't automatically ours to retry. Transient failures are transient — so if the same 500 comes back on every attempt, something else is wrong, and it's a request to fix rather than one to wait out.

The usual culprits surface as a 500 instead of a clean 4xx:

  • a date range beyond the stored window — only daily (D) granularity is limited, to about two years; a daily job reaching further back (say, all of 2023) fails rather than returning a validation error. Weekly (W) and monthly (M) granularity are kept for all time, so switch to one of those for older ranges;
  • an expired or revoked key;
  • the wrong environment or region for your key.

These come back as an InternalServerError with a GatewayError detail:

{
"status_code": 500,
"type": "InternalServerError",
"detail": { "type": "GatewayError" }
}

Your actual response includes a detail.message with more specifics — worth quoting if you contact support.

So when a 500 repeats, check the request, the key, and the environment before treating it as transient.

A Jobs submit is not idempotent — retrying a submit that actually succeeded creates a second, separate job, with its own job_id and result files. On an ambiguous failure, list your jobs before resubmitting rather than firing the request again.

Getting help​

If you're stuck — whether a call failed outright or the surface just doesn't look the way you expect — email support@edited.com with the details that pin down what you hit:

  • On MCP: the tool name and arguments you called; the full error envelope, if there was one — plenty of problems arrive without an error at all; serverInfo.version and the surface fingerprint from your initialize response (see Versioning); and your session ID — read the mdmcp+data://session_id resource right after the failing call so EDITED can find your requests in the logs.
  • On the REST APIs: the method and URL you called, the request body, and the HTTP status and response body you got back. For a Jobs problem, include the job_id.