pydantic/monty · error
gather item is not a Coroutine, ExternalFuture, or GatherFut
Error message
gather item is not a Coroutine, ExternalFuture, or GatherFuture
What it means
When committing a gather, each item must be pollable: a Coroutine, ExternalFuture, or GatherFuture. If an item is anything else, this panic fires — the gather machinery only accepts awaitable-like values, so encountering another type means the earlier awaitability check or conversion is missing or heap state is corrupted.
Source
Thrown at crates/monty/src/bytecode/vm/async_exec.rs:268
}
HeapReadOutput::GatherFuture(child_gather) => {
if let Some(value) = poll_settled_gather(&child_gather, self.heap)? {
Poll::Ready(value)
} else {
drop(child_gather);
// Both the inc_ref and the awaiter that owns it are
// handed to the nested frame, which releases them when
// it settles; until then nothing is committed for this
// slot, so an error above needs no cleanup here.
self.heap.inc_ref(gather_id);
let sub_awaiter = Awaiter::GatherSlot {
gather: gather_id,
source: item_id,
};
return Ok(Some(self.open_gather_commit(item_id, sub_awaiter, Some(idx))));
}
}
_ => panic!("gather item is not a Coroutine, ExternalFuture, or GatherFuture"),
};
match poll {
Poll::Ready(value) => frame.results[idx] = Some(value),
Poll::Pending => {
frame.pending_children.insert(item_id, smallvec![idx]);
}
}
frame.next += 1;
}
Ok(None)
}
/// Settles a fully-committed frame.
///
/// With nothing left in flight the gather goes straight to `Completed` with
/// its result list (this covers the empty `gather()` too); otherwise itView on GitHub (pinned to adc986b362)
Solutions
- Verify gather items are awaited-eligible before constructing results (mirroring CPython's `An asyncio.Future, a coroutine or an awaitable is required` TypeError)
- File a bug with the reproducing async snippet if hit from valid Python code
- Run with --features memory-model-checks to hunt the underlying heap/refcount bug
Example fix
// before items = gather([1, 2]) # non-awaitables must be rejected earlier // after items = gather([coro1, coro2]) # only awaitables passed to gather
Defensive patterns
Strategy: validation
Validate before calling
# user-side equivalent guard in Python items = [it if asyncio.iscoroutine(it) or hasattr(it, '__await__') else ensure_future(it) for it in items]
Prevention
- Only pass awaitables (coroutines, futures, nested gathers) to gather()
- Never mutate gather inputs while awaiting
- Report panics from valid Python code as interpreter bugs
When it happens
Trigger: Internal: a gather() call contains an item that passed earlier validation but by commit time is not Coroutine/ExternalFuture/GatherFuture — e.g. an item replaced on the heap mid-commit, or a code path (like gather over a resolved non-awaitable) that skipped validation.
Common situations: Interpreter development on async_exec.rs; a gather fed results that were prematurely resolved or overwritten; heap corruption from a refcount bug.
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 commit frame id is not a GatherFuture
- 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/2510a8d7c326d16c.
Report an issue: GitHub.