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
- Log both rows (observation vs expected) and diff them field-by-field to find the diverging column
- If a generated column diverges, compare the engine's computation with Model::apply for that column and fix the wrong side
- If bytes diverge, check row_to_bytes round-trip for the failing value and the normalize_rows logic
- 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
- Keep the model oracle in the same PR as engine semantic changes (generated columns, normalization)
- Run the dst property suite on every engine change with fixed seeds in CI
- Log both target and model rows on divergence to speed up diagnosis
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
- cannot serialize refs without a typespace
- length didn't fit in `u32`
- Deletion for non-existent table {table_id:?}... huh?
- missing system table sequence id for sequence {} of table {}
- system tables cannot have schedules, but table {}: {sch:?}
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/58f020a88a5ae556.
Report an issue: GitHub.