Errors
Every failure answers in the same shape: a list, because one request can be wrong in several places at once, and each entry says what is wrong, where, and what to do instead.
{ "errors": [ { "code": "DQL_UNKNOWN_FIELD", "message": "unknown field 'fundng' at 1:18; did you mean 'funding'?", "position": { "line": 1, "column": 18, "offset": 17, "length": 6 }, "hint": "did you mean 'funding'?" } ]}Branch on code. It is stable. message explains and may be reworded between releases, and hint
is advice, not a contract. position is present whenever the fault has a place in the query text:
line and column are 1-based, offset is 0-based, and length covers the offending token, so an
editor can underline it exactly.
What the language refuses
Section titled “What the language refuses”Each of these was produced by running the query beside it through the parser. The messages are the server’s own.
DQL_SYNTAX
Section titled “DQL_SYNTAX”The text is not a query. The position is where reading stopped and the message names what was expected there.
funding >{ "errors": [ { "code": "DQL_SYNTAX", "message": "unexpected end of input at 1:11; expected an expression", "position": { "line": 1, "column": 11, "offset": 10, "length": 0 }, "hint": "expected an expression" } ]}Underline the position. POST /v2/dql/parse answers this without running anything, which is what an editor should call on every keystroke.
DQL_UNKNOWN_FIELD
Section titled “DQL_UNKNOWN_FIELD”A name that is not a field. The message suggests the nearest one it knows.
any(venues where fundng > 0){ "errors": [ { "code": "DQL_UNKNOWN_FIELD", "message": "unknown field 'fundng' at 1:18; did you mean 'funding'?", "position": { "line": 1, "column": 18, "offset": 17, "length": 6 }, "hint": "did you mean 'funding'?" } ]}Read GET /v2/dql/catalogue for the fields that exist rather than carrying a list in your client.
DQL_UNKNOWN_FUNCTION
Section titled “DQL_UNKNOWN_FUNCTION”A name that is not a function.
any(venues where emma(close, 20) > 0){ "errors": [ { "code": "DQL_UNKNOWN_FUNCTION", "message": "unknown function 'emma' at 1:18; did you mean 'ema'?", "position": { "line": 1, "column": 18, "offset": 17, "length": 15 }, "hint": "did you mean 'ema'?" } ]}The catalogue lists every function with its signature.
DQL_UNKNOWN_VENUE
Section titled “DQL_UNKNOWN_VENUE”A venue code the platform does not have. The message lists the ones it does.
any(venues where venue = BINANCE-PERP){ "errors": [ { "code": "DQL_UNKNOWN_VENUE", "message": "unknown venue 'BINANCE-PERP' at 1:26; known: BYBIT-PERP, HYPERLIQUID, KRAKEN-FUTURES, OKX-PERP", "position": { "line": 1, "column": 26, "offset": 25, "length": 12 }, "hint": "known: BYBIT-PERP, HYPERLIQUID, KRAKEN-FUTURES, OKX-PERP" } ]}Read GET /v2/venues. A venue the platform is still onboarding is not queryable until it appears there.
DQL_UNKNOWN_CURRENCY
Section titled “DQL_UNKNOWN_CURRENCY”A quote currency that exists on no listing.
any(venues where quote = USDD){ "errors": [ { "code": "DQL_UNKNOWN_CURRENCY", "message": "unknown currency 'USDD'", "position": { "line": 1, "column": 26, "offset": 25, "length": 4 }, "hint": "did you mean 'USD'?" } ]}The catalogue’s currencies is the whole set. DQL never converts between them, so the spelling has to match.
DQL_UNKNOWN_ASSET
Section titled “DQL_UNKNOWN_ASSET”A base asset the platform does not have.
base = BITCOIN{ "errors": [ { "code": "DQL_UNKNOWN_ASSET", "message": "unknown asset 'BITCOIN'", "position": { "line": 1, "column": 8, "offset": 7, "length": 7 }, "hint": "known: BTC, ETH, SOL" } ]}The catalogue’s assets is the whole set.
DQL_UNKNOWN_INSTRUMENT
Section titled “DQL_UNKNOWN_INSTRUMENT”An instrument code that does not exist — often the base asset written where the instrument belongs.
instrument = BTC{ "errors": [ { "code": "DQL_UNKNOWN_INSTRUMENT", "message": "unknown instrument 'BTC'", "position": { "line": 1, "column": 14, "offset": 13, "length": 3 }, "hint": "known: BTC-PERP, ETH-PERP, SOL-PERP" } ]}Instruments are BTC-PERP, not BTC. The catalogue’s instruments lists them.
DQL_SCOPE
Section titled “DQL_SCOPE”A venue-scoped field used as though it belonged to the instrument. Funding is a fact about one venue’s listing; an instrument has several.
funding > 0{ "errors": [ { "code": "DQL_SCOPE", "message": "'funding' is venue-scoped; wrap it in any(venues where …), all(…), count(…) or an aggregate", "position": { "line": 1, "column": 1, "offset": 0, "length": 7 }, "hint": "wrap in any(venues where ...) / all(...) / count(...) or an aggregate" } ]}Say which venues you mean: any(venues where funding > 0), or all, count, or an aggregate.
DQL_NESTING
Section titled “DQL_NESTING”A quantifier inside a quantifier. There is one level of venues, so the inner one would have nothing to range over.
any(venues where any(venues where funding > 0)){ "errors": [ { "code": "DQL_NESTING", "message": "quantifiers cannot be nested", "position": { "line": 1, "column": 18, "offset": 17, "length": 29 } } ]}Flatten the condition.
DQL_TYPE
Section titled “DQL_TYPE”An operation on a value of the wrong kind. Summing prices across venues is a category error, not a small inaccuracy — the result would be a number with no meaning.
sum(venues, mark) > 0{ "errors": [ { "code": "DQL_TYPE", "message": "sum requires an additive field; mark is a price", "position": { "line": 1, "column": 1, "offset": 0, "length": 17 }, "hint": "additive: oi, volume_24h, turnover_24h, bid_size, ask_size, volume, the depth functions, or arithmetic over those" } ]}Sum only additive fields; the catalogue’s additive says which. For a price across venues, use max, min or an average of your own.
DQL_TIMEFRAME_REQUIRED
Section titled “DQL_TIMEFRAME_REQUIRED”A series function with no period to read at. A moving average is a different number on every timeframe, so the platform will not choose one for you.
any(venues where ema(close, 20) > close){ "errors": [ { "code": "DQL_TIMEFRAME_REQUIRED", "message": "series function 'ema' needs a timeframe: add 'timeframe 15m' or a trailing argument", "position": { "line": 1, "column": 18, "offset": 17, "length": 14 } } ]}Add timeframe 1h to the query, or give the function its own: ema(close, 20, 1h).
DQL_TIMEFRAME_UNSUPPORTED
Section titled “DQL_TIMEFRAME_UNSUPPORTED”A period the platform does not store. The message lists the ones it does.
any(venues where sma(close, 3) > 0) timeframe 7m{ "errors": [ { "code": "DQL_TIMEFRAME_UNSUPPORTED", "message": "timeframe '7m' is not supported; supported: 1m, 2m, 3m, 5m, 15m, 30m, 1h, 4h, 12h, 1d", "position": { "line": 1, "column": 37, "offset": 36, "length": 9 } } ]}Use a period from the catalogue’s timeframes.
DQL_TIMEFRAME_MISMATCH
Section titled “DQL_TIMEFRAME_MISMATCH”Two series of different periods compared as though they lined up. They do not: one bar of the first is not one bar of the second.
any(venues where crossover(ema(close, 20, 1h), ema(close, 50, 4h))){ "errors": [ { "code": "DQL_TIMEFRAME_MISMATCH", "message": "series timeframes differ (1h vs 4h)", "position": { "line": 1, "column": 18, "offset": 17, "length": 49 } } ]}Read both at the same period.
DQL_ARGUMENT
Section titled “DQL_ARGUMENT”An argument outside what the function accepts. The message states the range.
any(venues where ema(close, 0) > 0) timeframe 1h{ "errors": [ { "code": "DQL_ARGUMENT", "message": "argument 'n' of ema must be an integer in 1…500", "position": { "line": 1, "column": 29, "offset": 28, "length": 1 } } ]}Use a window inside the stated range.
DQL_DUPLICATE_CLAUSE
Section titled “DQL_DUPLICATE_CLAUSE”A clause given twice. The platform will not guess which one you meant.
venues_listed > 0 timeframe 1h timeframe 4h{ "errors": [ { "code": "DQL_DUPLICATE_CLAUSE", "message": "clause 'timeframe' given twice", "position": { "line": 1, "column": 32, "offset": 31, "length": 9 }, "hint": "each clause may appear at most once" } ]}Give it once.
DQL_AS_OF_RANGE
Section titled “DQL_AS_OF_RANGE”An instant outside what can be answered — in the future, or before the earliest data retained.
any(venues where funding > 0) as of 2030-01-01T00:00:00Z{ "errors": [ { "code": "DQL_AS_OF_RANGE", "message": "as_of is in the future", "position": { "line": 1, "column": 31, "offset": 30, "length": 2 }, "hint": "the server clock is 2026-09-23T12:00:05Z" } ]}The catalogue’s earliest_retained is the floor; the present is the ceiling.
What the request refuses
Section titled “What the request refuses”These are about the request rather than about the query, so no query produces them and none is shown.
| code | status | what it means |
|---|---|---|
DQL_JSON_SCHEMA |
400 | The request body is not the shape the endpoint takes. path points at the offending member, as a JSON pointer. |
DQL_VERSION |
400 | A language version other than 1 was asked for. There is only one. |
DQL_LIMIT |
400 | The request is within the grammar but past a batch limit — too many listings, too many rows, or a response too large. The message states both the figure and the limit. |
DQL_COMPLEXITY |
400 | The query is within the grammar but costs more than the limits allow. POST /v2/dql/parse returns a query’s cost, so this can be seen before it is hit. |
AUTH_REQUIRED |
401 | The endpoint needs a key and none was sent. |
AUTH_INVALID |
401 | The key is unknown, revoked, expired, or the header is not Bearer <key>. |
KEY_IN_URL |
400 | A key was sent as a query parameter. Query strings are written to logs and browser history, so the key should be treated as compromised and replaced. |
PLAN_LIMIT |
403 | The request is valid but reaches past what the plan includes — usually further back in history. |
RATE_LIMITED |
429 | A per-second, per-day or stream limit of the plan. Retry-After says when to come back. |
UNAVAILABLE |
503 | The platform cannot answer yet; retry in a minute. |
A 400 from POST /v2/dql/parse is not a failure of the API: it is the answer you asked for.