pydantic/monty · error
dict_keys view must always reference a dict
Error message
dict_keys view must always reference a dict
What it means
The HeapRead-based DictKeysView accessor reads the backing dictionary from the heap and panics if the id does not resolve to a Dict entry. As with the trait version, this is unreachable by construction and signals heap corruption or an id-reuse bug under the safe HeapReader API.
Source
Thrown at crates/monty/src/types/dict_view.rs:66
impl DictKeysView {
/// Creates a new keys view over an existing dictionary heap entry.
#[must_use]
pub fn new(dict_id: HeapId) -> Self {
Self { dict_id }
}
/// Returns the underlying dictionary heap id.
#[must_use]
pub fn dict_id(self) -> HeapId {
self.dict_id
}
}
impl<'h> HeapRead<'h, DictKeysView> {
fn dict(&self, vm: &mut VM<'h>) -> HeapObjectRead<'h, Dict> {
let HeapReadOutput::Dict(dict) = vm.heap.read(self.get(vm.heap).dict_id) else {
panic!("dict_keys view must always reference a dict");
};
dict
}
/// Compares this keys view to a mutable set using set membership semantics.
pub(crate) fn eq_set(&self, other: &HeapRead<'h, Set>, vm: &mut VM<'h>) -> RunResult<bool> {
dict_keys_eq_set_like(
&self.dict(vm),
other.get(vm.heap).len(),
|key, vm| other.contains(key, vm),
vm,
)
}
/// Compares this keys view to a frozenset using set membership semantics.
pub(crate) fn eq_frozenset(&self, other: &HeapRead<'h, FrozenSet>, vm: &mut VM<'h>) -> RunResult<bool> {
dict_keys_eq_set_like(
&self.dict(vm),View on GitHub (pinned to adc986b362)
Solutions
- Fix the refcount path that lets the dict be freed while the view exists (views must count as readers/refs).
- Verify the view's dict_id is incremented at construction and released via py_dec_ref_ids.
- Run the relevant test binary with `--features memory-model-checks` to catch the stale-id path.
Example fix
// before
let view = DictKeysView { dict_id }; // borrowed id
// after
heap.inc_ref(dict_id);
let view = DictKeysView { dict_id }; // owned, cleaned up via py_dec_ref_ids Defensive patterns
Strategy: type-guard
Validate before calling
// check the read resolves to a Dict before further use
if !matches!(vm.heap.read(view.get(vm.heap).dict_id), HeapReadOutput::Dict(_)) { return Err(ViewError::stale_dict()); } Prevention
- Views must participate in refcounting via py_dec_ref_ids
- Increment the dict refcount when constructing a view from a borrowed id
- Exercise dict views under --features memory-model-checks after heap changes
When it happens
Trigger: Any keys-view operation (eq_set, iteration, len) when the view's stored dict_id resolves to a non-Dict HeapReadOutput — i.e. the dict was freed and its id recycled while the view handle was live.
Common situations: Memory-model CI after refcount changes; debugging reports of wrong-typed heap reads.
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
- dict view must always reference a dict
- entry just allocated
- gather commit frame id is not a GatherFuture
- gather item is not a Coroutine, ExternalFuture, or GatherFut
- Cannot get identity of Dereferenced object
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/c6b0e96383135d33.
Report an issue: GitHub.