Skip to content
DezfilDocsv0.1.0

Limits

Find every limit Dezfil holds requests to, what you get when you reach one, and the setting that changes it.

At a limit, Dezfil either cuts an answer short and says so, or refuses the request with a status and an error code.

Try the first kind. This query asks for 1,001 rows, one more than a query’s answer holds unless an admin changes it:

curl

Terminal
curl -s http://localhost:3000/api/query \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT range AS n FROM range(1001)"}' \
| jq -c '{rowCount, shown: (.preview | length), previewTruncated}'

jq -c prints three parts of the answer on one line. Install jq if your system lacks it.

Output
{"rowCount":1001,"shown":1000,"previewTruncated":true}
  • <YOUR_TOKEN> is your API token. The API quickstart shows how to create one.
  • range(1001) makes 1,001 numbered rows, so you need no dataset to try it.
  • rowCount counts every row of the result.
  • preview holds the first rows, up to Rows shown in results, and previewTruncated is true when rows were left out.

On the SQL page the same query shows Showing the first 1,000 of 1,001 rows. Save as dataset or Download to keep them all. Both take every row.

At the limitYou getFor example
An answer with more rows or features than it holdsThe answer, with a field that says it is cut shortpreviewTruncated: true
A request over a sizeA 4xx status and an error code, before any work. Nothing changes.413 upload_too_large
An answer, or the work, over a size or memory budget422, or 400 for the memory of people’s SQL, and a code. No part of the answer comes back.422 query_result_too_large
Work that runs past its time408, or 504 for a link import’s download, and a code that names the limit. The work stops.408 query_timeout
A full queue, or too many requests409, 429 or 503. Retry later.429 rate_limited

An MB, here, in Settings and in Dezfil’s messages, is 1,048,576 bytes, a MiB: the 32 MB that query_result_too_large names is 33,554,432 bytes. Only Engine memory and Trusted engine memory count an MB as 1,000,000 bytes.

Most refusals at a setting’s limit say in their message which setting changes it, such as An admin can change "Query time limit". A few call the setting by another name than Settings › Limits does: the label that GET /api/instance/settings gives each setting is the one the message uses. Errors shows the parts of an error answer.

An admin changes most limits in Settings › Limits. A row with a lock is decided by the server: the line under it names the variable that changes it, except Largest image, which is fixed.

From a script, send the new value with <YOUR_ADMIN_TOKEN>, a token an admin’s account created; any other account’s token answers 403 forbidden:

curl

Terminal
curl -s -X PATCH http://localhost:3000/api/instance/settings \
-H "Authorization: Bearer <YOUR_ADMIN_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"previewRows": 2000}' \
| jq -c '.settings.previewRows | {value, source, locked}'
Output
{"value":2000,"source":"stored","locked":false}
  • previewRows is the key of Rows shown in results. The table below gives each limit’s key and variable.
  • source is stored for a value saved in Settings, environment for a variable, or default.
  • A key that a variable sets answers 409 setting_locked, and nothing changes.
  • To go back to the default, send {"previewRows": null}.

GET /api/instance/settings reads every limit in effect, for an admin. Any signed-in account reads previewRows and renderCapFeatures from GET /api/config.

Configuration shows how to set a variable and which value wins.

SettingVariableSettings keyDefaultValuesWhat it doesChanges
Largest uploadDEZFIL_UPLOAD_MAX_MBuploadMaxMb5120 MB1 to 102,400 in Settings; any number above 0 as a variableSize cap for one uploaded file.In Settings, live; by variable, after a restart
Data processing time limitDEZFIL_DATA_PROCESSING_TIMEOUT_SdataProcessingTimeoutS3600 seconds60 to 21,600 in Settings; any number above 0 as a variableTime to receive one upload, and, counted apart, time for one data processing job, such as an import.In Settings, live; by variable, after a restart
Largest link importDEZFIL_REMOTE_MAX_MBremoteMaxMb2048 MB1 to 102,400 in Settings; any number above 0 as a variableSize cap for a URL or object-store import.In Settings, live; by variable, after a restart
Link import time limitDEZFIL_REMOTE_TIMEOUT_SremoteTimeoutS300 seconds10 to 3,600 in Settings; any number above 0 as a variableTime for one link import’s whole download.In Settings, live; by variable, after a restart
OpenStreetMap areaDEZFIL_OSM_MAX_KM2osmMaxKm210000 km²1 to 1,000,000 in Settings; any number above 0 as a variableThe largest area one OpenStreetMap import may cover.In Settings, live; by variable, after a restart
Overture areaDEZFIL_OVERTURE_MAX_KM2overtureMaxKm225000 km²1 to 1,000,000 in Settings; any number above 0 as a variableThe largest area one Overture import of places may cover; other themes may cover more or less, by how dense they are.In Settings, live; by variable, after a restart
Query time limitDEZFIL_QUERY_TIMEOUT_SqueryTimeoutS60 seconds5 to 600 in Settings; any number above 0 as a variableTime for one query, whether the SQL people run, a layer, an inspection, a preview or a published map.In Settings, live; by variable, after a restart
Rows shown in resultsDEZFIL_PREVIEW_ROWSpreviewRows1000 rows10 to 100,000 in Settings; any number above 0 as a variableRow cap for result previews.In Settings, live; by variable, after a restart
Features drawn per layerDEZFIL_RENDER_CAP_FEATURES250000 featuresAny number above 0The most features a layer draws, and the count past which a points layer is drawn from tiles.By variable, after a restart
Bytes drawn per layerDEZFIL_RENDER_CAP_BYTES134217728 bytesAny number above 0, rounded down to a whole number of at least 1The largest answer one layer may draw from, in bytes of uncompressed JSON.By variable, after a restart
Tools running at onceDEZFIL_OPERATION_CONCURRENCYoperationConcurrency11 to 8 in Settings; any number above 0 as a variable, rounded down to a whole number of at least 1Tool runs at the same time; they share the engine that runs people’s SQL.In Settings, live; by variable, after a restart
Tools waitingDEZFIL_OPERATION_QUEUE_MAXoperationQueueMax201 to 200 in Settings; any number above 0 as a variable, rounded down to a whole number of at least 1Tool runs that may wait for a turn.In Settings, live; by variable, after a restart
Time limit per tool runDEZFIL_OPERATION_TIMEOUT_SoperationTimeoutS600 seconds30 to 7,200 in Settings; any number above 0 as a variableTime for one tool run, not counting its wait for a turn.In Settings, live; by variable, after a restart
Images at onceDEZFIL_EXPORT_RENDER_CONCURRENCYexportRenderConcurrency21 to 8 in Settings; any number above 0 as a variable, rounded down to a whole number of at least 1Images the server draws at the same time.In Settings, live; by variable, after a restart
Time limit per imageDEZFIL_EXPORT_RENDER_TIMEOUT_SexportRenderTimeoutS90 seconds10 to 300 in Settings; any number above 0 as a variableTime for one image, its wait for a turn included.In Settings, live; by variable, after a restart
Requests per visitorDEZFIL_PUBLIC_RATE_LIMITpublicRateLimit60 every 10 seconds1 to 10,000 in Settings; any number above 0 as a variableRequests one visitor may make to published maps, counted by network address across every published map.In Settings, live; by variable, after a restart
Tile requests per visitorDEZFIL_PUBLIC_TILE_RATE_LIMITpublicTileRateLimit600 every 10 seconds1 to 100,000 in Settings; any number above 0 as a variableTile requests one visitor may make to published maps, counted by network address across every published map.In Settings, live; by variable, after a restart
Engine memoryDEZFIL_QUERY_MEMORY_MB2048 MBAny number above 0Memory the engine that runs people’s SQL may use, shared by every query.By variable, after a restart
Trusted engine memoryDEZFIL_TRUSTED_MEMORY_MB3072 MBAny number above 0Memory the engine that imports and processes data may use; it may spill up to four times this to disk.By variable, after a restart
Slider preview rowsDEZFIL_SLIDER_PREVIEW_ROWS50000 rowsAny number above 0Source points transferred for interactive slider previews.By variable, after a restart
Published freshnessDEZFIL_PUBLISH_FRESHNESS_S30 secondsAny number above 0Cache window for published views.By variable, after a restart
Tile build time limitDEZFIL_TILE_BUILD_TIMEOUT_S600 secondsAny number above 0Time budget for each background tile-build stage.By variable, after a restart
Image request time limitDEZFIL_EXPORT_REQUEST_TIMEOUT_S20 secondsAny number above 0Deadline for each request made by the render page.By variable, after a restart
Tool attachment sizeDEZFIL_TOOL_ATTACHMENT_MAX_MB32 MBAny number above 0The largest file a tool hands back to the assistant or an agent, such as an exported image.By variable, after a restart
Run history depthDEZFIL_OPERATION_HISTORY_PER_SUBJECT20 runsAny number above 0, rounded down to a whole number of at least 1Runs kept in each run history, such as a workflow step’s; its latest success is always kept.By variable, after a restart
WhatLimitAt the limit
Rows in a query’s answerRows shown in resultsThe first rows, with previewTruncated: true
The whole answer, as JSON33,554,432 bytes (32 MiB)422 query_result_too_large, no rows
One value that is not geometry, as JSON2,097,152 bytes (2 MiB)422 query_result_too_large, no rows
Time for one queryQuery time limit408 query_timeout
Memory, shared by every queryEngine memory400 query_memory_exceeded
A text value, or the WKT of a dataset’s geometry, in a dataset inspection or a geometry-choice preview512 charactersIts first 512 and an ellipsis; the stored data stays whole

A value over 2 MiB refuses the whole answer:

curl

Terminal
curl -s -w "\n%{http_code}\n" http://localhost:3000/api/query \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d "{\"sql\": \"SELECT repeat('x', 3000000) AS value\"}"
Output
{"error":{"code":"query_result_too_large","message":"The result is too large to return: more than 32 MB in total, or one non-geometry value over 2 MB. Select fewer rows or columns, or shorten the value."}}
422

The two byte limits are fixed, with no setting. They hold four reads: the SQL console, dataset inspection, geometry-choice preview and the PostGIS five-row preview.

ReadHTTPMCP toolRows it shows
The SQL console, on the SQL pagePOST /api/queryrun_sqlRows shown in results
A dataset inspection, on a dataset’s pageGET /api/tables/{name}inspect_table50
The geometry-choice preview, in Set geometryPOST /api/tables/{name}/geometry/previewpreview_table_geometry50
The PostGIS five-row previewPOST /api/connections/postgis/{id}/previewpreview_postgis_relation5

A value’s quotes and escaping count toward its size. A geometry column counts toward the whole answer only, whether it travels as WKT or GeoJSON; in a dataset inspection, only the dataset’s own geometry column does. Text that holds WKT or GeoJSON counts as text.

Row and engine-memory limits still apply: a result below both byte ceilings can fail the engine-memory limit while the query runs.

Downloads and saved datasets take the complete result. SQL, table and layer file exports stream every row, above both byte limits. Errors says what to do at each read.

An inspection that is still too large keeps the dataset’s page and its Set geometry panel from opening. It also blocks tool column pickers, SQL schema inventory and completion, workflow dataset reads and facts, and automatic layer addition after a tool run.

A tool run can then report a failure even though the dataset has already been written. Existing layer rendering, dataset map features, file exports and deleting the dataset from Data use other reads and keep working. To open the dataset again, see A dataset’s page does not open.

A filter’s distinct values, a categorical classification, category widgets and value search hold each text value to 2 MiB too. The first two answer the same 422, a category widget shows the code as its own error, and value search names the layer under refusedLayers and leaves its rows out.

Query time limit must stay below Time limit per tool run.

WhatLimitAt the limit
One uploaded fileLargest upload413 upload_too_large
A .zip or .kmz file, unpackedLargest upload413 archive_too_large
Receiving an upload, then processing it, eachData processing time limit408 data_processing_timeout
An upload that stops sending60 seconds without a byte408 upload_stalled
One import from a link or cloud storageLargest link import413 remote_too_large
The download of a link importLink import time limit504 remote_timeout
The area of an OpenStreetMap importOpenStreetMap area413 area_too_large
The area of an Overture importOverture area, by theme413 area_too_large
The answer of the OpenStreetMap server to an importTwice Overpass response budget413 remote_too_large
The OpenStreetMap server’s time to answerTime budget per query, and 30 seconds more502 remote_fetch_failed
One statement of a PostGIS preview30 seconds, fixed408 query_timeout
Memory for imports and other data workTrusted engine memory422 engine_memory_exceeded
A template’s archive150 MB, and Largest upload unpacked413 template_archive_too_large or template_unpacked_too_large
A profile picture10 MB, fixed413 upload_too_large
A profile picture’s size in pixels64 million, fixed413 image_too_large
Receiving a profile picture120 seconds, fixed408 data_processing_timeout
Processing a profile picture20 seconds with its wait for a turn, one at a time and eight waiting, fixed408 data_processing_timeout, or 503 operation_queue_full

Data processing time limit also holds imports from links, OpenStreetMap, Overture and PostGIS, refreshes, geometry changes, template installs and exports of a dataset or a project.

When it runs out, the work stops, and data that was there before stays as it was.

Time budget per query and Overpass response budget are in Data and services, with their variables and defaults.

Overture area is the area for places. Each other theme takes a share of it:

Overture themeLargest area
PlacesOverture area
Buildings, AddressesA fifth of it
TransportationHalf of it
Base · land & waterFour times it
DivisionsTwenty times it

A reverse proxy in front of Dezfil has a body limit of its own, which must allow your largest upload. Reverse proxy and HTTPS shows how to set it.

WhatLimitAt the limit
Features in one layerFeatures drawn per layerA points layer draws as tiles. Another layer answers render_cap_exceeded.
One layer’s answer, as JSONBytes drawn per layerA points layer draws as tiles. Another layer answers render_bytes_exceeded.
A slider, Overture or OpenStreetMap preview, or a sketch’s features, as JSONBytes drawn per layer422 render_bytes_exceeded, with no part of the answer
One stage of building a layer’s tilesTile build time limitThe layer answers tile_build_failed, naming the time limit
Tools running at onceTools running at onceLater runs wait
Tool runs waitingTools waiting503 operation_queue_full
One tool run, waiting not countedTime limit per tool run408 operation_timeout
Runs of one workflow at once1409 run_in_flight
Addresses in one geocode runGeocode addresses400 invalid_request
Origins in one travel-time runTravel-time area400 invalid_request
One side of an exported image4,096 pixels400 invalid_request
Images rendering at onceImages at onceLater images wait
One image, waiting includedTime limit per image408 render_timeout

A layer that cannot draw still answers 200 from GET /api/layers/{id}/render. Its ok is false, and error.code names the limit. The map shows the layer as failed.

Geocode addresses and Travel-time area show how many one run takes at the current time limits, and grow with Time limit per tool run. They show on the Tools card of Settings › Limits, and Largest image on its Image export card. GET /api/instance/settings answers them as capacities.geocodeRows, capacities.isochroneOrigins and maxImageDimension.

WhatLimitAt the limit
One message as sent, with its history and page context131,072 bytes (128 KiB)413 assistant_submission_too_large
The page context in a message64 KiB of JSON413 assistant_context_too_large
What Dezfil tells the model about the page96 KiBDetails are left out, then 413 assistant_context_too_large
Model and tool steps in one requestAssistant stepsThe request ends with the event {"type":"done","reason":"budget"}
Requests open on the instance8409 assistant_capacity
One map check, waiting includedMap check time limitThe check answers render_timeout
A request’s unused place5 minutesThe place is freed
A download that a tool answers, over MCP or to the assistantTool attachment sizeA failed tool result with the code attachment_too_large
One MCP request, an uploaded file inside it16,777,216 bytes (16 MiB)413 request_body_too_large
A file uploaded through MCPAbout 12 MiB: three bytes for every four of the request left after its other parts. Also Largest upload.413 request_body_too_large, or upload_too_large over Largest upload
One page of the schema catalogue, GET /api/catalogue/tables96 KiB422 catalogue_too_large

Assistant steps and Map check time limit are in the table of Set up the assistant, with their variables and defaults; the other settings named here are in the table above.

In the app, a message over its limit shows The message and its context are too large to send. Shorten the message. On the SQL page, your editor text and a summary of your last run travel with every message, so a long draft counts too.

A request holds one of the eight places from its reservation until it ends. One that waits for your confirmation keeps its place.

When all eight are taken, the pane says The assistant is at capacity: eight requests are open on this instance. GET /api/assistant/pending lists your waiting requests, and DELETE /api/assistant/runs/{id} frees one.

A detail Dezfil leaves out of what it tells the model comes with the address the model reads it from. When even the names do not fit, the message is refused.

Through MCP, a file travels inside the request as base64, which makes it a third larger.

To upload a bigger file, use Add data in the app or POST /api/tables over HTTP.

Every operation that takes a JSON body has a byte limit, and the API reference shows each one. An agent reads it from the API description as x-byte-limit:

curl

Terminal
curl -s http://localhost:3000/api/openapi.json \
-H "Authorization: Bearer <YOUR_TOKEN>" \
| jq '.paths["/api/query"].post.requestBody["x-byte-limit"]'
Output
16777216
WhatLimitAt the limit
A JSON bodyThe operation’s x-byte-limit413 and the code its x-byte-error names: request_body_too_large, or assistant_submission_too_large for an assistant message
Any body but a file upload, until all of it arrives300 seconds408 request_timeout

Dezfil counts a body’s bytes as they arrive, whitespace and escaping included, and refuses a larger body before it parses it. Nothing changes.

A file upload, POST /api/tables, has no byte limit in the description: Largest upload holds it.

Dezfil counts requests in three places: visitors reading published maps, sign-ins, and current-password checks. Other requests, with a token or a session, have no rate limit.

WhoLimitAt the limit
A visitor reading a published map: its data, widgets and rendersRequests per visitor, every 10 seconds429 rate_limited
A visitor’s map tilesTile requests per visitor, every 10 seconds429 rate_limited
Failed sign-ins for one account, and from one addressFailed sign-ins before a pause, within 15 minutes429 rate_limited, with Retry-After
Wrong current passwords when you change your password or emailThe count per account, kept apart from sign-ins429 rate_limited, with Retry-After
Sign-ins and password checks working at onceTwo run at a time. Six sign-ins may wait, and two current-password checks or sign-in links, which run one at a time; each waits up to 5 seconds.503 authentication_busy, with Retry-After: 1

The visitor limits are in Settings › Limits, on the Public requests card. The sign-in counts are in Settings › Security, on the Sign-in card, and in Security and rules with their defaults.

Each visitor is counted by network address, and an IPv6 address with its whole /64. Behind a proxy that DEZFIL_TRUSTED_PROXIES does not list, every visitor shares the proxy’s count: see Trusted proxies.

A sign-in refusal gives the wait in its answer, as Errors shows. A visitor’s count starts again after its 10 seconds.

An OpenStreetMap import answers rate_limited too when the Overpass server refuses it. To avoid the public server’s limits, point Address on the OpenStreetMap card in Settings › Data & services, or DEZFIL_OVERPASS_URL, at your own Overpass server.

An upload answers 413 with a web page instead of JSON

Section titled “An upload answers 413 with a web page instead of JSON”

A reverse proxy refused the upload before it reached Dezfil. Raise the proxy’s body limit as Reverse proxy and HTTPS shows.

The server decides it, and the line under the row names the variable that changes it. Change the variable and restart, as Configuration shows.

Query time limit must stay below Time limit per tool run. Raise the tool run’s limit first, then the query’s.

A geocode or travel-time run is refused as too large

Section titled “A geocode or travel-time run is refused as too large”

The dataset has more rows than one run takes. Filter it first, or raise Time limit per tool run; Geocode addresses and Travel-time area show the new number.

  • Errors: the parts of an error answer, and what to do about each common code.
  • Configuration: set a variable, and see which value wins.
  • How the API works: sign-in, edit revisions and paging.
Dezfil · Apache-2.0docs from 7439201b