> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# BTQL multiline query formatting error

export const plans_0 = "Any"

export const deployments_0 = "Any"

export const data_plane_version_0 = undefined

export const use_case_0 = "Use case - Submitting BTQL queries (especially multiline queries) in the POST /btql JSON body and handling validation errors when queries are not encoded correctly."

<Note>
  **Applies to:**

  * Plan - {plans_0}
  * Deployment - {deployments_0}
  * {data_plane_version_0}
  * {use_case_0}
</Note>

## 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

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "error": "Invalid request",
  "errors": [
    {
      "code": "invalid_union",
      "unionErrors": [
        { "issues": [{ "code": "invalid_type", "expected": "string", "received": "undefined", "path": ["query"], "message": "Required" }], "name": "ZodError" },
        { "issues": [{ "code": "invalid_type", "expected": "object", "received": "undefined", "path": ["query"], "message": "Required" }], "name": "ZodError" }
      ],
      "path": ["query"],
      "message": "Invalid input"
    }
  ]
}
```

The `/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 the `query` 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:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{ "query": "select * from project_logs('88888888-8888-8888-8888-888888888888') limit 20" }
```

### Option 2: Escape newlines as `\n`

If you want to keep the query readable, encode line breaks explicitly as `\n` inside the JSON string:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{ "query": "select *\nfrom project_logs('88888888-8888-8888-8888-888888888888')\nlimit 20" }
```

### Working curl example

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
curl --location 'https://api.braintrust.dev/btql' \
--header 'Authorization: Bearer sk-your-api-key' \
--header 'Content-Type: application/json' \
--data '{"query": "select * from project_logs('\''88888888-8888-8888-8888-888888888888'\'') limit 20"}'
```

Replace the API URL with your data plane API URL if you are self-hosted.

## 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.

## References

* [SQL / BTQL API access — Braintrust docs](https://www.braintrust.dev/docs/reference/sql#api-access)
* [BTQL reference](https://www.braintrust.dev/docs/reference/btql)
