pydantic/monty · error
gather commit frame id is not a GatherFuture
Error message
gather commit frame id is not a GatherFuture
What it means
During async gather commit processing, step_gather_commit reads the heap entry identified by GatherCommit::gather and expects it to be a GatherFuture. If the heap read returns any other variant, this panic fires. It is an internal invariant: only code that just created a gather future should ever push a commit frame for it, so a mismatch means heap bookkeeping is corrupted.
Source
Thrown at crates/monty/src/bytecode/vm/async_exec.rs:215
awaiter,
parent_slot,
next: 0,
results: (0..item_count).map(|_| None).collect(),
pending_children: PendingChildren::new(),
}
}
/// Commits `frame`'s items left-to-right into result slots or pending
/// children, spawning coroutine children and installing awaiters on
/// external futures as it goes.
///
/// Stops early at a `Pending` nested gather, returning the frame the caller
/// must commit before this one can continue; `Ok(None)` means every item is
/// committed. Any error leaves the items handled so far in `frame`, which
/// [`Self::unwind_gather_commits`] settles.
fn step_gather_commit(&mut self, frame: &mut GatherCommit) -> Result<Option<GatherCommit>, RunError> {
let HeapReadOutput::GatherFuture(gather) = self.heap.read(frame.gather) else {
panic!("gather commit frame id is not a GatherFuture")
};
let gather_id = frame.gather;
while frame.next < frame.results.len() {
let idx = frame.next;
let item_id = gather.get(self.heap).items[idx];
if let Some(slots) = frame.pending_children.get_mut(&item_id) {
// Dedup: We've already registered this item in this commit pass —
// this is a duplicate item (e.g. `gather(coro, coro)`). Just
// append the new slot index to the existing entry.
slots.push(idx);
frame.next += 1;
continue;
}
let poll = match self.heap.read(item_id) {
HeapReadOutput::Coroutine(coro) => {
// Reject reuse up-front: either the coroutine is no longerView on GitHub (pinned to adc986b362)
Solutions
- Reproduce with a minimal async gather snippet and file a bug against monty with the code
- Check for a refcount/heap bug: run with --features memory-model-checks to validate heap invariants
- Inspect commit_gather_tree/open_gather_commit to confirm only fresh GatherFuture ids are stored in GatherCommit frames
Example fix
// before (interpreter bug)
let frame = GatherCommit { gather: wrong_id, .. };
// after
let HeapReadOutput::GatherFuture(_) = self.heap.read(gather_id) else { panic!(...) };
let frame = GatherCommit { gather: gather_id, .. }; Defensive patterns
Strategy: try-catch
Try / catch
// this is an interpreter-internal panic, not a catchable library error // isolate: run each async snippet in a fresh session so a corrupted heap cannot poison subsequent runs
Prevention
- Report the reproducing snippet to the monty maintainers
- Run --features memory-model-checks on async/gather changes
- Keep HeapId bookkeeping changes out of GatherCommit construction
When it happens
Trigger: An internal bug where frame.gather points at a heap entry that was replaced, freed, or never a GatherFuture (e.g. refcount bug causing reuse, or wrong HeapId stored in the commit frame).
Common situations: Not user-triggerable in normal operation; surfaces during interpreter development, after changes to gather/await machinery, or under heap corruption from another bug (possibly exposed with memory-model-checks).
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
- gather item is not a Coroutine, ExternalFuture, or GatherFut
- Awaiter::GatherSlot gather id is not a GatherFuture
- resolve_child called on a gather that was never awaited
- gather_id doesn't point to a GatherFuture
- Cannot get identity of Dereferenced object
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/914e8fedea59c89e.
Report an issue: GitHub.