clockworklabs/SpacetimeDB · error · anyhow::Error

insert_matches: accepted row diverged from model

Error message

insert_matches: accepted row diverged from model

What it means

Property InsertMatches failed: the engine accepted an insert, but the row it reports storing differs from the row predicted by the reference model oracle. Accepted rows carry engine-computed generated columns, so divergence means engine and model disagree on row content (generated-column values, normalization, or row encoding) — this is the harness detecting a suspected engine bug or a stale model, not a caller mistake.

Source

Thrown at crates/dst/src/engine/properties.rs:107

        matches!(interaction, Interaction::Insert { .. })
    }

    fn check(
        &self,
        _interaction: &Interaction,
        observation: &Observation,
        expected: &Observation,
    ) -> anyhow::Result<()> {
        let Observation::Inserted { outcome } = observation else {
            anyhow::bail!("insert_matches: insert produced unexpected observation");
        };
        let Observation::Inserted { outcome: expected } = expected else {
            unreachable!("InsertMatches only subscribes to insert interactions");
        };

        match (outcome, expected) {
            (InsertOutcome::Accepted(row), InsertOutcome::Accepted(expected)) => {
                anyhow::ensure!(row == expected, "insert_matches: accepted row diverged from model");
            }
            (InsertOutcome::UniqueConstraintViolation, InsertOutcome::UniqueConstraintViolation) => {}
            (InsertOutcome::Accepted(_), InsertOutcome::UniqueConstraintViolation) => {
                anyhow::bail!("insert_matches: target accepted row rejected by model");
            }
            (InsertOutcome::UniqueConstraintViolation, InsertOutcome::Accepted(_)) => {
                anyhow::bail!("insert_matches: target rejected row accepted by model");
            }
        }

        Ok(())
    }
}

struct CommitMatches;

impl EngineProperty for CommitMatches {
    fn observes(&self, interaction: &Interaction) -> bool {

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Log both rows (observation vs expected) and diff them field-by-field to find the diverging column
  2. If a generated column diverges, compare the engine's computation with Model::apply for that column and fix the wrong side
  3. If bytes diverge, check row_to_bytes round-trip for the failing value and the normalize_rows logic
  4. Re-run with the failing seed after the fix to confirm the property holds

Example fix

// before: property failure gives only the message
anyhow::ensure!(row == expected, "insert_matches: accepted row diverged from model");

// after (debugging aid): report the differing columns
for (i, (a, b)) in row.iter().zip(expected.iter()).enumerate() {
    if a != b { log::error!("col {i}: target={a:?} model={b:?}"); }
}
Defensive patterns

Strategy: try-catch

Try / catch

match suite.observe(&interaction, &observation) {
    Ok(()) => {}
    Err(e) if e.to_string().contains("insert_matches: accepted row diverged from model") => {
        // persist the failing (interaction, observation) pair for shrinking;
        // this is an engine/model disagreement, never auto-retry
        shrinker.save_minimal_case(&interaction, &observation, &e);
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Running the dst property suite; inserting into a table whose generated columns are computed differently by the engine and by Model::apply; a change in row normalization or row_to_bytes encoding that was mirrored in only one of engine/model.

Common situations: Engine changes to generated columns or insert normalization without updating the model oracle; new table shapes in SchemaPlan exercising untested value types; encoding round-trip changes in the table layer.

Related errors


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