stalwartlabs/stalwart · error
Invalid jump position
Error message
Invalid jump position
What it means
In the expression parser, update_jmp_pos patches the jump offset of a previously emitted JmpIf instruction once its target position is known. If the item at the recorded position is not a JmpIf, the recorded jump position is corrupted — a parser invariant violation. The panic is compiled in only under `cfg(test)`, so in release builds the mismatch is silently ignored and the failure surfaces as a test-time "Invalid jump position" panic.
Source
Thrown at crates/common/src/expr/parser.rs:259
_ => {}
}
}
}
fn dec_arg_count(&mut self) {
if let Some(x) = self.arg_count.last_mut() {
*x = x.saturating_sub(1);
}
}
fn update_jmp_pos(&mut self, jmp_pos: Option<usize>) {
if let Some(jmp_pos) = jmp_pos {
let cur_pos = self.output.len();
if let ExpressionItem::JmpIf { pos, .. } = &mut self.output[jmp_pos] {
*pos = (cur_pos - jmp_pos) as u32;
} else {
#[cfg(test)]
panic!("Invalid jump position");
}
}
}
}
impl BinaryOperator {
fn precedence(&self) -> i32 {
match self {
BinaryOperator::Multiply | BinaryOperator::Divide => 7,
BinaryOperator::Add | BinaryOperator::Subtract => 6,
BinaryOperator::Gt | BinaryOperator::Ge | BinaryOperator::Lt | BinaryOperator::Le => 5,
BinaryOperator::Eq | BinaryOperator::Ne => 4,
BinaryOperator::Xor => 3,
BinaryOperator::And => 2,
BinaryOperator::Or => 1,
}
}
}View on GitHub (pinned to e962003857)
Solutions
- Audit the parse path that pushes jmp_pos: ensure a JmpIf is emitted at exactly the recorded index before update_jmp_pos runs.
- Check that no code path replaces or reorders self.output entries between emitting JmpIf and patching it.
- Run the parser tests with debug output of self.output to find where the recorded slot no longer holds JmpIf.
Example fix
// before: emitting a non-jump item into a slot that had a pending JmpIf self.output[jmp_pos] = ExpressionItem::Const(...); // after: push new items; never overwrite pending JmpIf slots self.output.push(ExpressionItem::Const(...)); // then update_jmp_pos(Some(jmp_pos)) patches the untouched JmpIf
Defensive patterns
Strategy: type-guard
Type guard
fn is_jmp_if(item: &ExpressionItem) -> bool {
matches!(item, ExpressionItem::JmpIf { .. })
} Try / catch
// test-only panic; in library code prefer a no-op or assert with context:
if let Some(jmp_pos) = jmp_pos {
debug_assert!(matches!(self.output[jmp_pos], ExpressionItem::JmpIf { .. }),
"jmp slot {jmp_pos} does not hold JmpIf");
} Prevention
- Never overwrite or reorder self.output slots once a jump position has been recorded.
- Keep jmp recording and JmpIf emission adjacent in the parse code.
- Add debug_assert! invariants so mismatches surface immediately in dev builds.
When it happens
Trigger: Parsing an expression whose control-flow bookkeeping gets out of sync — e.g. a jump was recorded (jmp_pos pushed) but the output slot was later overwritten with a non-JmpIf item, or positions were recorded/emitted in the wrong order while parsing conditional operators. Running parser tests with such input triggers the panic inside update_jmp_pos, called from parse.
Common situations: Developers modifying the parser's output emission or jump bookkeeping (adding new operators or short-circuit handling) and running the test suite; malformed expressions exercising edge cases in jump patching during test runs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Failed to read {yaml_path:?}
- Node id {node_id} exceeds {MAX_NODE_ID}, panicking to avoid
- unwrap_tls called on non-TLS acceptor
- Sieve test failed: {}
- Failed to load the platform certificate verifier
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/0e4795c59d2ba52f.
Report an issue: GitHub.