API error codes, reasons and how to fix them
Every error the host.sh IP lookup API returns: HTTP status, machine-readable reason, what causes it and how to fix it, with a request that triggers it.
An error is an HTTP status of 400 or more with a JSON body (except 413, which is an HTML page from the web server): an errors array holding one object with the numeric code (the same as the status), a short message, a machine-readable reason and a detail sentence. Match on reason; message and detail are for people and can change.
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_LANGUAGE","detail":"lang must be one of en, de, es, fr, ja, pt-BR, ru, zh-CN"}]}
In a batch an invalid address gets the same object as its item in results, and the batch itself still answers 200.
All errors
| Status | Reason | Cause |
|---|---|---|
| 400 | BAD_REQUEST | A JSON body that isn't valid JSON |
| 400 | INVALID_IP_ADDRESS | ip (or the address in the path) is not an IPv4 or IPv6 address |
| 400 | INVALID_LANGUAGE | lang is not one of the supported languages |
| 400 | INVALID_FORMAT | format is not json or text, or format=text without exactly one single-value field |
| 400 | INVALID_CALLBACK | callback is not a JavaScript identifier |
| 400 | NO_IPS | A batch with no addresses |
| 400 | TOO_MANY_IPS | A batch with more than 100 addresses |
| 401 | TOKEN_MISSING | A batch without a token |
| 403 | TOKEN_INVALID | The token is unknown, disabled or has no permission for this endpoint |
| 403 | TOKEN_REQUIRED | A tokenless request asked for something other than your own IP |
| 404 | (none) | No such endpoint |
| 405 | METHOD_NOT_ALLOWED | The endpoint doesn't take this HTTP method |
| 413 | (none) | The request body is over 64 KB; the answer is an HTML page, not JSON |
| 429 | TOO_MANY_REQUESTS | Over the tokenless rate limit |
| 5xx | (none) | A server error; retry later |
400 Bad request
BAD_REQUEST
The body was sent as Content-Type: application/json but isn't valid JSON. Check the quoting, or let your HTTP library encode the body.
curl -H "Content-Type: application/json" -d '{bad' https://api.host.sh/v2/lookup/
{"errors":[{"code":400,"message":"Bad request","reason":"BAD_REQUEST","detail":"The request could not be parsed"}]}
A batch body that starts with [ or { but isn't valid JSON gets the same reason with the detail The body is not valid JSON.
INVALID_IP_ADDRESS
ip, or the address in /v2/lookup/{ip}, is not an IPv4 or IPv6 address. Host names are not looked up; resolve them first. Leading and trailing spaces are ignored.
curl -H "Authorization: Bearer YOUR_TOKEN" "https://api.host.sh/v2/lookup/?ip=1.2.3"
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_IP_ADDRESS","detail":"ip must be an IPv4 or IPv6 address"}]}
Without a token, ip= gets TOKEN_REQUIRED first.
INVALID_LANGUAGE
lang must be one of en, de, es, fr, ja, pt-BR, ru or zh-CN, written exactly like that.
curl "https://api.host.sh/v2/lookup/?lang=xx"
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_LANGUAGE","detail":"lang must be one of en, de, es, fr, ja, pt-BR, ru, zh-CN"}]}
INVALID_FORMAT
format must be json or text, and format=text needs fields with exactly one path to a single value (not an object). There are three details:
curl "https://api.host.sh/v2/lookup/?format=xml"
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_FORMAT","detail":"format must be json or text"}]}
curl "https://api.host.sh/v2/lookup/?format=text"
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_FORMAT","detail":"format=text needs exactly one field, e.g. fields=geo.country.code"}]}
curl "https://api.host.sh/v2/lookup/?format=text&fields=geo.country"
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_FORMAT","detail":"format=text needs a field with a single value, not an object"}]}
INVALID_CALLBACK
A JSONP callback must be a JavaScript identifier, or identifiers joined by dots such as app.onIp: letters, digits, _ and $, not starting with a digit, not a reserved word like function, at most 64 characters.
curl "https://api.host.sh/v2/lookup/?callback=1abc"
{"errors":[{"code":400,"message":"Bad request","reason":"INVALID_CALLBACK","detail":"callback must be a JavaScript identifier"}]}
NO_IPS
A batch body that is empty or holds no addresses. Send a JSON array, an object with an ips array, or addresses as text.
curl -H "Authorization: Bearer YOUR_TOKEN" -d '[]' https://api.host.sh/v2/lookup/batch/
{"errors":[{"code":400,"message":"Bad request","reason":"NO_IPS","detail":"Send a JSON array of addresses, e.g. [\"8.8.8.8\", \"1.1.1.1\"]"}]}
TOO_MANY_IPS
A batch takes at most 100 addresses. Split longer lists into several requests.
{"errors":[{"code":400,"message":"Bad request","reason":"TOO_MANY_IPS","detail":"Send at most 100 addresses per request"}]}
401 Unauthorized
TOKEN_MISSING
The batch endpoint needs a token, as a Bearer header or ?token=. A token in the body is not read there, because the body is the list of addresses.
curl -d '["8.8.8.8"]' https://api.host.sh/v2/lookup/batch/
{"errors":[{"code":401,"message":"Unauthorized","reason":"TOKEN_MISSING","detail":"Send a token as ?token=, a JSON body field or an Authorization: Bearer header"}]}
403 Forbidden
TOKEN_INVALID
The token is unknown, has been disabled, or its plan doesn't include this endpoint. Check that it is copied whole, with no spaces or quotes around it. When a request has a token in more than one place, the one the API reads first counts; see Authentication.
curl -H "Authorization: Bearer not-a-token" https://api.host.sh/v2/lookup/
{"errors":[{"code":403,"message":"Forbidden","reason":"TOKEN_INVALID","detail":"The token is unknown, disabled or has no permission for this endpoint"}]}
TOKEN_REQUIRED
Without a token the API only looks up your own IP. Asking for another address with ip= or /v2/lookup/{ip}, or sending ua= or al=, needs a token.
curl "https://api.host.sh/v2/lookup/?ip=8.8.8.8"
{"errors":[{"code":403,"message":"Forbidden","reason":"TOKEN_REQUIRED","detail":"Looking up anything but your own IP needs a token"}]}
404, 405 and 413
404 Not found
There is no endpoint at this path. The answer has no reason. Check the version prefix and the trailing slash: /v2/lookup/ and /v2/lookup/batch/ end with one.
curl https://api.host.sh/v2/nothing/
{"errors":[{"code":404,"message":"Not found"}]}
METHOD_NOT_ALLOWED
Lookups take GET, HEAD and POST, the batch endpoint only POST, and /v2/ip/ only GET and HEAD. OPTIONS, a browser's CORS preflight, gets 204 everywhere.
curl -X DELETE https://api.host.sh/v2/lookup/
{"errors":[{"code":405,"message":"Not allowed","reason":"METHOD_NOT_ALLOWED","detail":"This endpoint does not support the request method"}]}
413 Request Entity Too Large
The request body is over 64 KB. The web server answers before the API sees the request, so the body is a short HTML page, not JSON. A batch of 100 addresses is far below the limit.
429 Too many requests
TOO_MANY_REQUESTS
More than 10 tokenless requests a minute from one IP address. Wait the number of seconds in the Retry-After header, or send a token. See Rate limits.
{"errors":[{"code":429,"message":"Too many requests","reason":"TOO_MANY_REQUESTS","detail":"Too many requests without a token, retry after a few seconds or use a token"}]}
5xx Server errors
A 500 ({"errors":[{"code":500,"message":"Internal server error"}]}) is a fault on the host.sh side, and 502 to 504 can come from the network in between. Retry with a growing delay.
This page as Markdown: /docs/errors/index.md