PRQL/prql · error · Error

`side`: expected inner, left, right or full, found

Error message

`side`: expected inner, left, right or full, found {val}

What it means

The PRQL compiler throws this when the `side` parameter of a `join` transform is not one of the four supported join kinds: inner, left, right, or full. The value is matched as a literal string (including quotes); anything else, including typos, unquoted identifiers, or wrong-case values, fails resolution. The error tells you exactly what was found so you can correct the `side:` argument.

Solutions

  1. Change the side value to one of "inner", "left", "right", or "full" (quoted strings)
  2. Note that plain `join` defaults to inner, so omit `side:` entirely if inner is intended
  3. For cross joins, use the `cross` transform instead of `join side:"cross"`

Example fix

// before
from employees
join side:outer salaries (==emp_id)
// after
from employees
join side:"full" salaries (==emp_id)
Defensive patterns

Strategy: validation

Validate before calling

let side = "full";
if (!["inner", "left", "right", "full"].includes(side)) {
  throw new Error(`side must be one of inner/left/right/full, got ${side}`);
}

Type guard

const isJoinSide = (v) => ["inner","left","right","full"].includes(v);

Prevention

When it happens

Trigger: Calling `join side:<val> ...` with any side value other than the exact literals "inner", "left", "right", or "full" — e.g. `join side:inner` (unquoted), `side:"outer"`, `side:"Inner"`, `side:"cross"`, or a non-literal expression.

Common situations: Users coming from SQL write `outer` or `cross` instead of the PRQL-supported values; forgetting the quotes so the value is parsed as an identifier; using wrong capitalization after converting SQL queries.

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/e8ca23266de1ea1a. Report an issue: GitHub.

Appendix: source

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

                let [side, with, filter, tbl] = unpack::<4>(func.args);

                let side = {
                    let span = side.span;
                    let ident = side.clone().try_cast(
                        ExprKind::into_literal,
                        Some("`side`"),
                        "inner, left, right or full",
                    )?;

                    // these must match the values of JoinSide defined in std.prql
                    match ident.to_string().as_str() {
                        "\"inner\"" => JoinSide::Inner,
                        "\"left\"" => JoinSide::Left,
                        "\"right\"" => JoinSide::Right,
                        "\"full\"" => JoinSide::Full,

                        val => {
                            return Err(Error::new(Reason::Expected {
                                who: Some("`side`".to_string()),
                                expected: "inner, left, right or full".to_string(),
                                found: val.to_string(),
                            })
                            .with_span(span))
                        }
                    }
                };

                let filter = Box::new(filter);
                let with = Box::new(with);
                (TransformKind::Join { side, with, filter }, tbl)
            }
            "group" => {
                let [by, pipeline, tbl] = unpack::<3>(func.args);

                let by = Box::new(self.coerce_into_tuple(by)?);

View on GitHub (pinned to e164e249b9)