diem/diem · error
Target locals out contains new local
Error message
Target locals out contains new local
What it means
This unreachable!() fires inside generate_block in the test-generation bytecode generator. The generator tracks an 'abstract state' of locals; after emitting bytecode for a block it verifies that the target locals output introduced no locals that were not already known to the state. Hitting this panic means the local-tracking logic produced an inconsistent local assignment, which the generator assumes is impossible.
Source
Thrown at language/testing-infra/test-generation/src/bytecode_generator.rs:707
&& *current_availability == BorrowState::Available
{
state = self.apply_instruction(
fn_context,
state,
&mut bytecode,
Bytecode::MoveLoc(*i as u8),
true,
)?;
state = self.apply_instruction(
fn_context,
state,
&mut bytecode,
Bytecode::Pop,
true,
)?;
}
} else {
unreachable!("Target locals out contains new local");
}
}
// Update the module to be the module that we've been building in our abstract state
Some((bytecode, state))
}
/// Generate the body of a function definition given a set of starting `locals` and a target
/// return `signature`. The sequence should contain at least `target_min` and at most
/// `target_max` instructions.
pub fn generate(
&mut self,
fn_context: &mut FunctionGenerationContext,
locals: &[SignatureToken],
fh: &FunctionHandle,
acquires_global_resources: &[StructDefinitionIndex],
module: &mut CompiledModule,
call_graph: &mut CallGraph,
) -> Option<Vec<Bytecode>> {View on GitHub (pinned to fc4714a8ea)
Solutions
- Inspect the failing seed and the generated instruction sequence to find which bytecode writes a new local index
- Fix the AbstractState join/merge so target locals only contain locals already present in the state, or remap the new local to an existing slot
- If the instruction legitimately creates a local, update generate_block to handle it instead of relying on the unreachable arm
- Add a regression proptest case with the failing seed
Example fix
// before
} else {
unreachable!("Target locals out contains new local");
}
// after
} else if let Some(existing) = state.local_index_for(&new_local) {
state.remap_target_local(existing);
} else {
unreachable!("Target locals out contains new local");
} Defensive patterns
Strategy: validation
Validate before calling
assert!(target_out.iter().all(|l| state.locals().contains_key(l)), "target locals out introduces unknown local");
Type guard
fn locals_known(state: &AbstractState, out: &BTreeSet<LocalIndex>) -> bool {
out.iter().all(|l| state.local_exists(*l))
} Prevention
- Unit-test AbstractState merge for all new bytecode variants
- Keep local index allocation centralized in one module
- Run the proptest suite with shrinking enabled to capture failing seeds
When it happens
Trigger: Running the Move test generator (proptest-driven bytecode generation) on a generated program whose generated instructions create a new local in the target locals out-set instead of only reusing/merging existing ones; typically a generator bug after adding a new bytecode variant that writes to a fresh local index.
Common situations: Developers extending the test generator with new instruction kinds, or changing local index allocation in AbstractState, run randomized generation and hit this panic on some seed.
Related errors
- main() cannot currently be bytecode
- Can't inhabit native structs
- Unsupported inhabitation. Type: {:#?}
- Invalid number of children for basic block {:?}
- Unable to write key to file at specified path
AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04).
Data as JSON: /api/errors/f6fd2debe6d21fbd.
Report an issue: GitHub.