clockworklabs/SpacetimeDB · critical

a row was a sequence trigger but there was no generated colu

Error message

a row was a sequence trigger but there was no generated column for it.

What it means

Panics while decoding a BSATN table row in the generated client bindings. A row whose encoding marks it as a sequence trigger (a placeholder where a generated/sequence column value belongs) must be completed from the generated-columns byte slice, but `Self::decode(gen_cols)` failed — typically because the slice is empty or shorter than the value. In practice the binary payload does not match the schema the bindings were generated from.

Source

Thrown at crates/bindings/src/table.rs:1295

    /// Is this value one that will trigger a sequence, if any,
    /// when used as a column value.
    /// For numeric types, this is `0`.
    fn is_sequence_trigger(&self) -> bool;
    /// Should invoke `BufReader::get_{Self}`, for example `BufReader::get_u32`.
    fn decode(reader: &mut &[u8]) -> Result<Self, DecodeError>;
    /// Read a generated column from the slice, if this row was a sequence trigger.
    #[inline(always)]
    fn maybe_decode_into(&mut self, gen_cols: &mut &[u8]) {
        if self.is_sequence_trigger() {
            *self = Self::decode(gen_cols).unwrap_or_else(|_| sequence_decode_error())
        }
    }
}

#[cold]
#[inline(never)]
fn sequence_decode_error() -> ! {
    unreachable!("a row was a sequence trigger but there was no generated column for it.")
}

macro_rules! impl_seq_trigger {
    ($($get:ident($t:ty),)*) => {
        $(
            impl SequenceTrigger for $t {
                #[inline(always)]
                fn is_sequence_trigger(&self) -> bool { *self == 0 }
                #[inline(always)]
                fn decode(reader: &mut &[u8]) -> Result<Self, DecodeError> {
                    reader.$get()
                }
            }
        )*
    };
}

impl_seq_trigger!(

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Regenerate the module bindings against the currently published module (`spacetime generate`) so the row layout matches
  2. Redeploy the module so server and client agree on the schema, then rebuild the client
  3. Verify the transport is not truncating frames (proxy/load-balancer body limits) and that both sides target the same database

Example fix

# before
# client decodes subscription updates with bindings generated from an old schema:
# panic: a row was a sequence trigger but there was no generated column for it.

# after
spacetime generate --lang rust --out-dir ./module-bindings
# then rebuild the client against the refreshed bindings
Defensive patterns

Strategy: validation

Validate before calling

// before subscribing, confirm the client's schema matches the published module
let remote = api.database_schema(&db_identity).await?;
if remote.hash != LOCAL_MODULE_SCHEMA_HASH {
    anyhow::bail!("bindings out of date: regenerate with `spacetime generate`");
}

Try / catch

Decoding happens inside the bindings and panics rather than returning Result. Isolate row decoding in std::panic::catch_unwind at your message-pump boundary, log the module schema hash on failure, and run a regenerate-and-restart recovery path.

Prevention

When it happens

Trigger: Decoding a subscription table update or query result whose BSATN rows contain sequence-trigger markers while the generated-columns slice is empty or truncated. Happens when bindings were generated from a different module schema than the server publishes (e.g. a column gained sequence/auto-inc generation) or when the byte buffer was sliced incorrectly.

Common situations: Stale generated bindings after redeploying a module with schema changes; a client built against module version A talking to a database running version B; truncated or corrupted WebSocket/HTTP payloads introduced by a proxy.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/8f6b18ec5cea7992. Report an issue: GitHub.