PRQL/prql · error · Error

`format`: expected csv or json, found

Error message

`format`: expected csv or json, found {format}

What it means

`std.from_text` supports only `"csv"` and `"json"` formats; anything else passed as the `format` argument fails with this error. The format must also be a literal string, since parsing happens at compile time.

Solutions

  1. Use `format:"csv"` or `format:"json"` exactly (lowercase, quoted).
  2. For other formats, convert the data to CSV/JSON before embedding it in PRQL.
  3. For JSONL, convert to a JSON array, since only standard JSON is supported.

Example fix

// before
from_text format:"xml" text:"<a/>"
// after
from_text format:"json" text:"[{\"a\": 1}]"
Defensive patterns

Strategy: validation

Validate before calling

const FORMATS = ['"csv"', '"json"'];
if (!FORMATS.includes(format)) throw new Error(`from_text format must be csv or json, got ${format}`);

Type guard

const isFromTextFormat = (v) => v === '"csv"' || v === '"json"';

Try / catch

try { compile(prql) } catch (e) { if (e.message.includes('`format`: expected csv or json')) { /* switch format or convert data */ } }

Prevention

When it happens

Trigger: Calling `from_text format:"xml" ...`, `format:'JSON'` (case mismatch), a misspelled format (`csvv`, `jsonl`), or a non-literal format expression.

Common situations: Assuming other formats (TSV, XML, parquet) are supported, using uppercase variants, or trying JSON Lines which is not plain `json`.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of PRQL/prql@e164e249b9 (2026-09-09). Data as JSON: /api/errors/86db2cdd20204d54. Report an issue: GitHub.

Appendix: source

Thrown at prqlc/prqlc/src/semantic/resolver/transforms.rs:538

                            found: format!("`{}`", write_pl(text_expr.clone())),
                        })
                        .with_span(text_expr.span));
                    }
                };

                let res = {
                    let span = format.span;
                    let format = format
                        .try_cast(ExprKind::into_literal, Some("`format`"), "csv or json")?
                        .to_string();
                    match format.as_str() {
                        "\"csv\"" => from_text::parse_csv(&text)
                            .map_err(|r| Error::new_simple(r).with_span(span))?,
                        "\"json\"" => from_text::parse_json(&text)
                            .map_err(|r| Error::new_simple(r).with_span(span))?,

                        _ => {
                            return Err(Error::new(Reason::Expected {
                                who: Some("`format`".to_string()),
                                expected: "csv or json".to_string(),
                                found: format,
                            })
                            .with_span(span))
                        }
                    }
                };

                let expr_id = text_expr.id.unwrap();
                let input_name = text_expr.alias.unwrap_or_else(|| "text".to_string());

                let columns: Vec<_> = res
                    .columns
                    .iter()
                    .cloned()
                    .map(|x| TyTupleField::Single(Some(x), None))
                    .collect();

View on GitHub (pinned to e164e249b9)