Applies to:
- Plan -
- Deployment -
Summary
Symptom:POST /btql returns a 400 with a Zod invalid_union error and "query": "Required", even though the request includes a query field.
Root cause: The query string spanned multiple lines with raw (unescaped) line breaks, producing a malformed JSON body. The query field never reached the server as a valid string, so validation failed.
Fix: Send the query as a single-line JSON string, or escape newlines as \n.
The error
/btql endpoint accepts query as either a string (SQL/BTQL text) or a parsed-query object. When the request body is malformed, query arrives as undefined and fails both branches of the union — which is why the error reports “expected string” and “expected object”. The error points at the request body encoding, not at your SQL.
Why multiline queries break
JSON string values cannot contain raw line breaks. A query written across several lines in a client like Bruno, Postman, or an editor may be sent with literal newline characters embedded in the JSON, which corrupts the body so thequery field is not parsed as a valid string.
This often is not something you type directly. Third-party or intermediary software that builds the HTTP request for you — API clients (Bruno, Postman, Insomnia), no-code and workflow tools, SDK wrappers, or an internal proxy that reserializes the body — can inject raw line breaks, reformat the payload, or alter quoting before the request reaches Braintrust. If the raw payload looks correct on your side but still fails, inspect the exact bytes the tool sends on the wire, or reproduce the call with a plain single-line curl to isolate whether the client is the source of the malformed body.
Solution
Option 1: Single-line query
Put the entire query on one line:Option 2: Escape newlines as \n
If you want to keep the query readable, encode line breaks explicitly as \n inside the JSON string:
Working curl example
Additional checks
- Drop the trailing semicolon. It is unnecessary in the JSON payload.
- Use straight quotes, not smart quotes. Copying a query from a rich-text editor can substitute curly quotes (
''"") that break parsing. Use'and". - Set
Content-Type: application/json. Without it, the body may not be parsed as JSON. - Use the project UUID, not the project name, inside
project_logs('...').
Notes
- The endpoint’s validation error does not clearly state that the body was malformed. Improving this error message is tracked internally.