dbt-labs/dbt-core · error · InvalidArgument

A join can not be both "inner" and "full_outer".

Error message

A join can not be both "inner" and "full_outer".

What it means

Thrown by `Table.join()` when both `inner=True` and `full_outer=True` are passed. These join types are mutually exclusive — a join is either an inner join or a full outer join, not both — so the library raises this InvalidArgument error before performing the join.

Source

Thrown at crates/dbt-agate/src/table.rs:1308

                    .unwrap_or(false);
                let columns = iter.next_kwarg::<Option<&Value>>("columns")?;
                iter.finish()?;

                let right_table = match right_table.downcast_object_ref::<AgateTable>() {
                    Some(table) => table,
                    None => {
                        return Err(Error::new(
                            ErrorKind::InvalidArgument,
                            format!(
                                "Table.join: right_table must be a Table: {right_table} found instead"
                            ),
                        ));
                    }
                };

                let join_type = if inner {
                    if full_outer {
                        return Err(Error::new(
                            ErrorKind::InvalidArgument,
                            "A join can not be both \"inner\" and \"full_outer\".",
                        ));
                    }
                    JoinType::Inner
                } else if full_outer {
                    JoinType::FullOuter
                } else {
                    JoinType::LeftOuter
                };

                let table = self.join(
                    right_table,
                    left_key,
                    right_key,
                    join_type,
                    require_match,
                    columns,

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Pass only one of `inner` or `full_outer` as True
  2. Omit both flags for the default join behavior
  3. Add validation in calling code that rejects conflicting join options
  4. If you need a different join type, check the supported JoinType variants (inner, full_outer) and pick one

Example fix

// before
table.join(right, 'k', 'k', inner=True, full_outer=True)
// after
table.join(right, 'k', 'k', inner=True)  # or full_outer=True, not both
Defensive patterns

Strategy: validation

Validate before calling

if inner and full_outer:
    raise ValueError('inner and full_outer are mutually exclusive')

Type guard

null

Try / catch

try:
    joined = table.join(right, lk, rk, inner=inner, full_outer=full_outer)
except Exception as e:
    if 'can not be both' in str(e):
        raise ValueError('choose either inner or full_outer') from e
    raise

Prevention

When it happens

Trigger: Calling `table.join(right, left_key, right_key, inner=True, full_outer=True)`, typically from code that builds join flags dynamically and sets both booleans.

Common situations: Programmatic join construction where flags accumulate from config or user options without a mutual-exclusion check; misunderstanding the boolean API (default join is already inner).

Understand the failure class

Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/faa94f240158579f. Report an issue: GitHub.