What They Are
The analytics datasets hold metrics and dimensions: counts, latencies, models, identifiers. Extraction functions add the text those rows point at.conversation(ConversationId) returns the whole thread as markdown, llm_readable_trace(TraceId, 8000) returns a trace as the evaluators read it, and llm_messages(TraceId) returns the chat messages of the trace’s model call.
LangWatch computes these values after the query runs, then puts them in the column you aliased. GET /api/v1/query/schema lists every function in its functions section, with the value it returns, the permissions it needs, and whether your key holds them.
Where You Can Call One
A function call has to be an aliased entry in the top levelSELECT list of a single statement:
WHERE, GROUP BY, ORDER BY, HAVING, a join condition, a subquery, a common table expression, a UNION branch or a nested expression is refused with APP_FUNCTION_POSITION. The reason is correctness: the database sees the key your function was given, not the value LangWatch computes from it, so a filter written that way would compare the identifier and return the wrong rows.
The alias is required. LangWatch finds the call by its output column name, so a call without one is refused with APP_FUNCTION_ALIAS_REQUIRED.
The first argument is the key and can be any expression the query already allows. Every other argument steers how the value is built and has to be written directly in the query rather than read from a column or a bound parameter.
The Functions
The schema endpoint publishes each function’s
encoding. A function marked json returns a string whose contents are JSON, so parse it back rather than treating it as prose.
Permissions
Every function that returns captured content requires the same permissions as the columns holding that content. Your key needs the captured input permission, the captured output permission, or both, depending on the function. A key missing one getsAPP_FUNCTION_GATED, naming the permission to ask for.
thread_traces carries no captured content and needs no content permission.
How Many Rows One Run Reads
Each function reads a capped number of distinct conversations, traces or spans per run, listed above and published by the schema endpoint. The cap counts distinct keys, so a query grouping ten thousand rows onto two hundred conversations costs two hundred reads. A query that would go past a cap answers422 with the code lwql_app_function_key_cap, naming the cap and how many keys it needed. That is deliberate: a result that quietly filled the first thousand cells and left the rest as raw identifiers would look complete and be wrong. Lower the LIMIT, group more coarsely, or page through with a keyset predicate on the dataset’s time column and trace identifier.
What A Response Tells You
Three things can shorten a result, and each one leaves a diagnostic behind:RESULT_TRUNCATEDwithmeta.ceilingset tohydratedBytesmeans trailing rows were dropped at the 32 MB response budget.APP_FUNCTION_VALUE_TRUNCATEDmeans one conversation or trace was larger than a single value may be, so that value was cut. Ask for a smaller token budget to choose what is kept.APP_FUNCTION_UNRESOLVED_KEYSmeans some rows are null because their conversation or trace identifier matched no record. Check the identifiers, and that the rows fall inside your retention window.
Example: Export A Week Of Conversations
Example: Read The Model Calls Of Failed Traces
messages holds a JSON string with an input and an output array, matching what the trace view shows for the same call.
Eval Functions
An eval function asks a question about a text and answers it per row. The text is normally an extraction function, which is the one place a function may be nested:eval takes two arguments and eval_criteria takes three. They are separate names because a function in the database has one fixed argument count, so the criteria form cannot be an optional third argument on eval.
The rules of the extraction functions all apply: the call is an aliased entry in the top level SELECT list, the arguments other than the text are written directly in the query, and the text may nest one extraction function, but not a second level.
What One Query Costs
Every distinct text is one call to the judge. Several eval functions over the same expression travel in that one call, so asking three questions of a conversation costs about the same as asking one:- A run judges at most 1,000 distinct texts, the same shape of cap the extraction functions carry. Past it the answer is
422with the codelwql_app_function_key_cap, naming the cap and how many texts the query needed. - A run whose texts together would exceed the per-query token budget answers
422with the codeinstant_eval_query_budget_exceeded, before anything is sent to the judge.
LIMIT, ask the extraction function for a smaller token budget, or run the statement as a job.
A text longer than the judge takes is cut before it is sent, keeping the start. Pass a token budget to the extraction function to choose what survives instead.
When A Row Is Not Judged
Judged columns areNullable. A null means the row was not judged, and the response says why:
INSTANT_EVAL_SKIPPEDmeans the text reached the judge and came back unanswered. The reasons ride inmeta: rate limited, too large even after being cut, or no judge configured on this deployment.APP_FUNCTION_UNRESOLVED_KEYSmeans the extraction produced no text at all, so the row was never sent to the judge.
GET /api/v1/query/schema lists every eval function with kind set to eval and available saying whether this project may call one. A call made while it may not is refused with APP_FUNCTION_GATED.