Errors
Errors raised by the renderer are returned as application/json regardless of the requested output format. The one exception is an over-sized request body: that is rejected by the reverse proxy in front of api.maproll.io and comes back as an HTML 413 page rather than the JSON shape below.
HTTP status codes
| Status | Meaning | When it happens |
|---|---|---|
200 OK | Success | Map rendered and returned. |
304 Not Modified | Cached — no body | Sent when If-None-Match matches the current ETag. |
400 Bad Request | Validation or parser failure | A parameter value is invalid — wrong type, out of range, missing scope, or a data/markers/routes/patterns/annotations string could not be parsed. |
404 Not Found | Unknown scope | The scope value is not in the loaded topology. |
413 Request Entity Too Large | Body too large | POST body exceeds 4 MB on api.maproll.io. Returned by the reverse proxy as an HTML page, not the JSON shape below. |
500 Internal Server Error | Topology missing | topology_missing — the scope resolved but its topology file could not be loaded. Should not occur in normal operation. |
Error shape
Every error response has this JSON structure:
{
"error": "error_code",
"message": "Human-readable description of the problem.",
"status": 400
}
error— a machine-readable code identifying the specific error.message— a human-readable explanation, often including the invalid value and what was expected.status— mirrors the HTTP status code.
Example 400 — invalid theme:
{
"error": "invalid_theme",
"message": "theme \"ocean\" not found. Available: light, light-blue, light-mono, dark, dark-blue, dark-mono",
"status": 400
}
Example 400 — missing scope:
{
"error": "missing_scope",
"message": "scope is required",
"status": 400
}
Example 404 — unknown scope:
{
"error": "invalid_scope",
"message": "Scope \"eu\" not found",
"status": 404
}
Example 400 — malformed data parameter:
{
"error": "invalid_data",
"message": "bad pair \"US-abc\" (expected id:value[:color])",
"status": 400
}
Example 400 — numeric and categorical values mixed in one request:
{
"error": "mixed_data_types",
"message": "data values must be either all numeric or all categorical labels, not a mix",
"status": 400
}
Common mistakes
Invalid scope
scope must exactly match a loaded topology ID. IDs are case-sensitive. Use the Scopes list to find the correct value.
# Wrong — lowercase
?scope=ro
# Correct
?scope=RO
Malformed data=
Each pair must be one of id:value, id:value:#rrggbb, id:#rrggbb, or id:label. The # must be URL-encoded as %23.
# Wrong — missing colon
?data=US,CN,DE
# Wrong — unencoded #
?data=US:100:#ff0000
# Wrong — looks like a typo'd hex (embedded # in a label is rejected)
?data=US:dem#ocracy
# Correct — numeric values
?data=US:100,CN:80,DE:60
# Correct — numeric + per-region color override
?data=US:100:%23ff0000,CN:80,DE:60
# Correct — color-only paint, no values
?data=US:%23dc2626,CN:%232563eb,DE:%2316a34a
# Correct — categorical labels (auto-categorical)
?data=US:NATO,CN:BRICS,DE:NATO
Mixing numeric and string values
A single request must commit to one kind of value — magnitudes for choropleth or labels for categorical, not both. Combining them returns 400 mixed_data_types. Color-only pairs (id:#hex) coexist with either kind, so a request like data=US:200,CN:150,DE:#ff0000 is fine; data=US:200,CN:BRICS is not.
Mixing data= and regions=
data= and regions= serve different modes. data= encodes numeric values, text labels, or per-region colors; regions= is highlight-only with a single shared accent. Passing both is not an error, but data= wins outright: whenever data= is present the highlight accent is not applied at all, and regions named only in regions= render in the plain land colour. Use one or the other.
Oversized POST body
Bodies up to 4 MB (4,194,304 bytes) are accepted: the renderer and the reverse proxy in front of api.maproll.io are set to the same ceiling. Past it, the proxy answers with an HTML 413 Request Entity Too Large page rather than the JSON error shape above. Consider:
- Reducing decimal precision in value fields.
- Omitting regions with
nullvalues if you only want to highlight a subset. - Splitting annotation strings that are close to the 200-character limit.
Too many regions
The maximum is 5000 regions per request. Requests exceeding this return:
{
"error": "too_many_regions",
"message": "region count exceeds limit (5000)",
"status": 400
}