-
SEO Learning Center
Broaden your SEO knowledge with resources for all skill levels.
-
The Beginner's Guide to SEO
If you're brand new to SEO, start here.
-
SEO Q&A
Get answers from the Moz Community.
-
Free Downloads and More
Quick access to whitepapers, reports, guides, webinars, and case studies.
-
Help Hub
Learn how to use Moz products.
-
Community & Events
Connect with over 600k online marketers.
-
SEO Training
Instructor-led classes and seminars
Error Handling
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": "4b812966-ba5c-45f1-a880-d7428d17ed73", "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": "fc1b1072-4885-4524-8ec2-03f98fe0d6f7", "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": "3f468098-a5e9-446f-ba96-8ec579035836", "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": "81de73df-3ca4-4c79-8775-6ae76c4db1d6", "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": "6f37c969-47eb-4e88-bca6-87a98c0dec55", "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": "40477815-0f6d-4e31-b653-56254c2ec7b9", "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": "4b821e1a-a3ac-4409-9810-94429872e6fe", "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": "c93c6f8d-85c0-4d07-9fa4-ac0c28395a04", "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.
{ "id": null, "jsonrpc": "2.0", "error": { "code": -32603, "httpStatus": 500, "data": {}, "message": "Internal error" } }
Rate Limiting
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.