diem/diem · error
Not allowed to assume update invariant
Error message
Not allowed to assume update invariant
What it means
A safety check in assert_or_assume_translated_invariants: update invariants (GlobalInvariantUpdate) may only be asserted, never assumed, because assuming an update invariant would be unsound (it describes state changes, not state). If the pass would emit an Assume of an update invariant, it panics instead.
Source
Thrown at language/move-prover/bytecode/src/global_invariant_instrumentation_v2.rs:666
/// xlated_invariants that is also in inv_set at the current location,
fn assert_or_assume_translated_invariants(
&mut self,
xlated_invariants: &[(Loc, GlobalId, Exp)],
inv_set: &BTreeSet<GlobalId>,
prop_kind: PropKind,
) {
let global_env = self.builder.global_env();
for (loc, mid, cond) in xlated_invariants {
if inv_set.contains(mid) {
// Check for hard-to-debug coding error (this is not a user error)
if inv_set.contains(mid)
&& matches!(prop_kind, PropKind::Assume)
&& matches!(
global_env.get_global_invariant(*mid).unwrap().kind,
ConditionKind::GlobalInvariantUpdate(..)
)
{
panic!("Not allowed to assume update invariant");
}
self.emit_invariant(loc, cond, prop_kind);
}
}
}
/// Emit an assert or assume for one invariant, give location and expression for the property
fn emit_invariant(&mut self, loc: &Loc, cond: &Exp, prop_kind: PropKind) {
self.builder.set_next_debug_comment(format!(
"global invariant {}",
loc.display(self.builder.global_env())
));
// No error messages on assumes
if prop_kind == PropKind::Assert {
self.builder
.set_loc_and_vc_info(loc.clone(), GLOBAL_INVARIANT_FAILS_MESSAGE);
}
self.builderView on GitHub (pinned to fc4714a8ea)
Solutions
- Use unmodified v2 instrumentation logic, which only assumes plain global invariants
- If customizing the pass, filter GlobalInvariantUpdate invariants out of Assume sets before calling emit_invariant
- Report upstream with the Move function/spec that reproduces it
Example fix
// before: assuming update invariant
let kind = PropKind::Assume;
// after: only assert update invariants
let kind = if is_update_inv { PropKind::Assert } else { PropKind::Assume }; Defensive patterns
Strategy: validation
Validate before calling
fn safe_prop_kind(inv_kind: &ConditionKind, desired: PropKind) -> PropKind {
if matches!(inv_kind, ConditionKind::GlobalInvariantUpdate(_)) { PropKind::Assert } else { desired }
} Type guard
fn is_update_invariant(kind: &ConditionKind) -> bool {
matches!(kind, ConditionKind::GlobalInvariantUpdate(_))
} Try / catch
// in custom emit logic:
if is_update_invariant(&inv.kind) && matches!(kind, PropKind::Assume) {
eprintln!("refusing to assume update invariant; emitting assert instead");
} Prevention
- Never mark GlobalInvariantUpdate invariants with PropKind::Assume in custom passes
- Filter update invariants out of assume sets before emitting
- Keep instrumentation translation logic aligned with upstream design
When it happens
Trigger: A translated invariant set marked as PropKind::Assume contains an update invariant — arising from a bug or modification in how invariants are translated/assigned prop kinds for a bytecode (e.g. around opaque calls or reads where update invariants should only be asserted).
Common situations: Patched instrumentation logic emitting assumes at points the original design only asserts; spec-language changes letting update invariants become applicable at assume points.
Related errors
- Invariant applicability not available
- self.saved_from_pre should be None
- saved_from_pre should be Some
- A global invariant must have a condition kind of either `Glo
- Expect a branch statement
AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04).
Data as JSON: /api/errors/fa995f74f82c9aa9.
Report an issue: GitHub.