Errors encountered while interacting with the Moz API are returned with the
appropriate HTTP status code and contain metadata along with detailed error
information in the response body. This guide describes the shape of an error
response, lists every error the API can return, and covers rate limiting.
Error Response Structure
An error response is a JSON-RPC 2.0 response object containing an error member
instead of a result member:
id: Echo of the ID provided by the client in the request. This is null
when the request could not be read at all, because in that case the API never
learns the ID you sent.
jsonrpc: JSON-RPC version of the API. Always 2.0.
error: An object describing what went wrong:
code: Use this to determine the error type. It is stable across message
wording changes.
status or httpStatus: The HTTP status code, repeated in the body for
convenience. Both spellings occur depending on which layer of the API
produced the error, so read whichever is present rather than assuming one.
message: A human-readable summary of the problem. Safe to log or display,
but do not match on its exact text.
data: Additional detail. This is an empty object for simple errors, and
for others may contain:
explanation: A longer description of why the error occurred.
issue: A machine-readable category. Stable, and intended for branching.
key: A dot-separated path to the request field the error relates to.
value: The offending value, where echoing it back is useful.
Here is an example of the JSON body of an error response returned by the Moz
API:
{"id":"c2c69346-2f26-499c-8360-bebe5b282683","jsonrpc":"2.0","error":{"code":-32652,"status":400,"data":{"explanation":"query is a required field and was not included.","issue":"param-is-missing","key":"query"},"message":"Please include a query"}}
Errors never carry HTTP response headers, with one exception: a per-method rate
limit response includes a Retry-After header. Rate limits applied at the edge
do not. See
Rate Limiting.
Error Reference
Every error the Moz API can return is listed below, ordered roughly by how often
you are likely to encounter it. Use code rather than message or the HTTP
status alone.
-32651 Authentication failed
HTTP 401. Your x-moz-token header is missing, malformed, or no longer
valid.
Check that the header is present and that the token has not been deleted or
regenerated on the Moz API dashboard. Retrying
will not help until the token is corrected.
{"id":"be770ccf-fe7d-41f3-b602-3c9f9aba9634","jsonrpc":"2.0","error":{"code":-32651,"status":401,"data":{},"message":"Missing or invalid authentication"}}
-32670 Insufficient quota
HTTP 403. Your account does not have enough quota remaining to complete the
request.
{"id":"2c11de0c-9c4f-41e2-9152-8810e87f98c2","jsonrpc":"2.0","error":{"code":-32670,"status":403,"data":{"explanation":"account does not have sufficient quota","issue":"insufficient-quota"},"message":"The account does not have enough quota remaining for current period."}}
Quota is checked before a method runs, so a request that would cost more than
your remaining balance is rejected without consuming any of it.
Check your balance with the
quota lookup method, which
consumes no quota itself. Quota resets monthly; some tiers also support
pay-as-you-go overages. Whether overages apply is set on your account rather
than something you switch on yourself, and the
Moz API dashboard shows whether they are
enabled. Note that a method may draw on a different quota than your main plan,
for example
beta methods -
the documentation for each method states which quota it uses.
-32652 Invalid parameters
HTTP 400. One or more parameters in params.data failed validation. This is
the most common error while integrating.
data.key identifies the offending field and data.issue categorises the
problem, so this error can be handled precisely in code. issue is one of:
param-is-missing: A required field was not supplied.
param-is-wrongtype: The field was supplied with the wrong type, for example
a string where a number is expected.
param-is-invalid: The field is the right type but the value is not
acceptable, for example a number outside the permitted range.
param-is-duplicate: The value conflicts with one that already exists.
{"id":"53ff5956-a2f6-4710-a03e-cf3b0e65a9a2","jsonrpc":"2.0","error":{"code":-32652,"status":400,"data":{"explanation":"at most 50 entries","issue":"param-is-invalid","key":"site_queries"},"message":"Site_queries must be less than 50 entries."}}
Validation runs before quota is checked, so a request rejected here consumes no
quota.
-32654 Invalid request ID
HTTP 400. The id field of your request does not meet the API's
requirements. There are three rules, and message states which one was broken:
The id must be present.
It must be longer than 24 characters.
It may contain only letters, numbers and hyphens.
A V4 UUID satisfies all three, and is the recommended choice. See
request construction.
{"id":"aaaaaaaaaaaaaaaaaaaaaaaa","jsonrpc":"2.0","error":{"code":-32654,"status":400,"data":{},"message":"Minimum Request ID length is 24."}}
-32601 Method not found
HTTP 400. The method you requested does not exist. Check it against the
method documentation in the left nav, and note that method names are
case-sensitive.
The message names the formal method name rather than the method string you sent,
so no.such.method is reported as NoSuchMethod. This is expected and not a
sign that your request was altered.
{"id":"779d5f3d-5790-4d8c-85c0-fce1103a22db","jsonrpc":"2.0","error":{"code":-32601,"status":400,"data":{},"message":"Action not found: NoSuchMethod"}}
-32600 Malformed request
HTTP 400, 413 or 415. Your request could not be accepted. Either it was
valid JSON but not a valid JSON-RPC 2.0 request, or it was declined before being
read at all.
Where the request was valid JSON but not a valid request object, the common
causes are:
jsonrpc is not exactly the string "2.0".
method is missing or is not a string.
id is neither a string nor a number.
The id field was omitted entirely. Omitting id makes the request a
JSON-RPC notification, and the Moz API does not support notifications.
A batch request was sent as an empty array. A batch must contain at least one
request.
This code is also returned when the body is declined before it is read, in which
case the HTTP status carries the reason: 413 if it exceeds the maximum size,
or 415 if its Content-Encoding or charset is not supported. There is no
data.key in these cases, because no field of the request was reached.
{"id":null,"jsonrpc":"2.0","error":{"code":-32600,"httpStatus":400,"data":{},"message":"jsonrpc must be \"2.0\""}}
-32700 Unparseable request body
HTTP 400. The request body could not be read at all, so the API could not
determine what you were asking for. Causes include invalid JSON such as a
missing bracket or a trailing comma, a body that is valid JSON but not an object
or array, and a truncated or corrupt gzip payload.
data.explanation carries the parser's own description of the problem,
including the character position where parsing failed, which is usually enough
to locate the mistake. Because the body was never read, id is null.
{"id":null,"jsonrpc":"2.0","error":{"code":-32700,"httpStatus":400,"data":{"explanation":"Expected double-quoted property name in JSON at position 85"},"message":"The request body could not be parsed."}}
-32655 Not found
HTTP 404. The request was valid, but the data you asked for does not exist.
data.key and data.value identify what could not be found.
This is distinct from an empty result. Some methods return a 404 rather than an
empty list when the subject of the request itself is unknown.
{"id":"ec03dcd2-9d5c-427b-acba-c6510c9c2308","jsonrpc":"2.0","error":{"code":-32655,"status":404,"data":{"key":"site_query","value":"example.com"},"message":"No data found for that query."}}
-32653 Request could not be completed
HTTP 400. The request was well-formed and passed validation, but could not
be carried out. This covers conditions specific to the method being called, so
message is the authoritative description of what went wrong.
{"id":"dd856678-5a60-4462-9eb5-78230b00147b","jsonrpc":"2.0","error":{"code":-32653,"status":400,"data":{},"message":"The request could not be completed."}}
-32658 Rate limited
HTTP 429. You have exceeded a rate limit for the method you called. See
Rate Limiting
for how to respond.
{"id":"ac5657d8-32fc-4da7-b40b-9ca727bf35f3","jsonrpc":"2.0","error":{"code":-32658,"status":429,"data":{"explanation":"Rate limit for the given action has been exceeded.","issue":"rate_limited","value":60},"message":"You have exceeded the request rate limit. Please slow down and try again."}}
The response also carries a Retry-After header holding the same number of
seconds as data.value.
-32603 and -32602 Server errors
HTTP 500. Something failed on our side. These are not caused by your
request, and the same request may well succeed on a retry.
Retry with an exponential backoff. If the error persists, contact
api@moz.com and include the request payload that failed.
The Moz API applies two independent kinds of rate limiting: limits enforced at
the edge, which apply to every request before it reaches the API, and limits
that an individual method may apply to itself. They return different error
codes, so use error.code to determine which one you have hit.
Edge rate limiting
Edge limits protect the API from clients sending too many requests, or too many
failing requests, in a short window. They apply to all traffic you send,
whatever method it calls, and there are three thresholds:
Authentication failures. Ten 401 or 403 responses within 5 minutes
result in a block lasting 30 minutes. This is the limit callers hit most
often: a client looping on a wrong or expired token reaches it within seconds
and is then locked out for the full half hour. If a request fails to
authenticate, stop and correct your credentials rather than retrying.
Client errors. Twenty responses in the 4xx range within 60 seconds
result in throttling. 404 and 429 responses are not counted towards it.
There is no fixed lockout - the limit clears by itself as your error rate
falls - but the remedy is to correct the error your requests are returning,
not to retry the same failing request more slowly.
Request volume. Two thousand requests within 60 seconds result in
throttling. Every request counts towards this, including ones that succeed.
Reduce the number of requests you have in flight at once and spread your work
out over time; this limit also clears by itself as your request rate falls.
Requests refused by any of these limits are answered with HTTP 429 and the
error code -32650. For example:
{"id":"unknown","jsonrpc":"2.0","error":{"code":-32650,"status":429,"data":{"explanation":"ip address is blocked","issue":"request-is-blocked","key":null},"message":"Your IP has been temporarily blocked due to bad requests."}}
A few details of that response are worth noting. The id is the literal string
"unknown" rather than the ID you sent, because the request is refused before
it is ever read, and data.key is null for the same reason. data.issue is
request-is-blocked, while the message and data.explanation vary with which
limit you reached - use error.code rather than matching on either of them.
Finally, these responses carry no Retry-After header, so nothing tells you
how long to wait. Where you must retry, use an exponential backoff - but the
reliable remedy is to fix whatever produced the errors, since a client that
keeps sending them will simply trip the limit again.
Per-method rate limiting
An individual method may carry its own rate limit, applied independently of the
edge limits above. Exceeding one returns HTTP 429 with the error code
-32658 - a different code from the edge limits, and the only rate limit
response that tells you how long to wait. It carries:
a Retry-After response header giving the number of seconds to wait,
the same number in data.value, and
data.issue set to rate_limited.
Honour that value rather than choosing your own backoff interval.
Where a method does apply one, two things are worth knowing. First, the limit
may be shared across all callers rather than applied per account, so it is
possible to be rate-limited by overall demand for a method without having sent
an unusual number of requests yourself. Second, the limit is specific to the
method being called - see the documentation for each method for its own limits.