SeaQL/sea-orm · error

trait bound ensured arity

Error message

trait bound ensured arity

What it means

`DeleteMany::filter_by_ids` builds a tuple-IN condition on the primary key and validates it via `column_tuple_in_condition(...).expect("trait bound ensured arity")`. The expectation is that the generic `IntoValueTuple` trait bounds guarantee every value's tuple length matches the primary key arity. A panic means values whose tuple arity mismatches the entity's composite primary key slipped through.

Source

Thrown at sea-orm-sync/src/query/delete.rs:212

    ///
    /// # Panics
    ///
    /// Should not panic.
    pub fn filter_by_ids<I>(mut self, values: I) -> Self
    where
        I: IntoIterator<Item = <E::PrimaryKey as PrimaryKeyTrait>::ValueType>,
    {
        self.query.cond_where(
            column_tuple_in_condition(
                &E::default().table_ref(),
                &E::primary_key_identity(),
                &values
                    .into_iter()
                    .map(|v| v.into_value_tuple())
                    .collect::<Vec<_>>(),
                DbBackend::Sqlite,
            )
            .expect("trait bound ensured arity"),
        );
        self
    }

    #[doc(hidden)]
    /// # Panics
    ///
    /// Panic if `ValueTuple` arity does not match primary key
    pub fn filter_by_value_tuples(mut self, values: &[ValueTuple], db_backend: DbBackend) -> Self {
        self.query.cond_where(
            column_tuple_in_condition(
                &E::default().table_ref(),
                &E::primary_key_identity(),
                values,
                db_backend,
            )
            .expect(""),
        );

View on GitHub (pinned to e29bcd1b41)

Solutions

  1. Pass primary key values with the exact arity: single value for one-column keys, `(a, b)` tuples for composite keys.
  2. Type the ids as `(<Entity as EntityTrait>::PrimaryKey)`-compatible tuples and let the compiler check.
  3. Add a compile-time test calling filter_by_ids for each entity to catch arity drift.

Example fix

// before
post_tag::Entity::delete_by_id(vec![tag_id]) // composite key needs pairs
// after
post_tag::Entity::delete_by_id(vec![(post_id, tag_id)])
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure ids arity matches the entity's primary key
let arity = <PostTag::PrimaryKey as PrimaryKeyTrait>::ValueType::arity(); // e.g. 2
let ok = ids.iter().all(|v| value_tuple_len(v) == arity);

Type guard

fn as_pk<E: EntityTrait>(v: E::PrimaryKey) -> E::PrimaryKey { v } // only correctly-arity keys typecheck

Prevention

When it happens

Trigger: Calling `delete_by_ids` / `filter_by_ids` with values whose `into_value_tuple()` produces a different number of elements than the entity's primary key arity — e.g. single values for a 2-column composite key or vice versa.

Common situations: Refactoring a table from single to composite primary key while old call sites still pass plain ids; mixing id types from different entities; deserializing ids from JSON into the wrong shape.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10). Data as JSON: /api/errors/ae1d52ef2011249c. Report an issue: GitHub.