rust-lang/rust · critical

not a module: {node:?}

Error message

not a module: {node:?}

What it means

Panic in hir_get_module (compiler/rustc_middle/src/hir/map.rs:420). Given a LocalModId, it constructs the owner HirId and expects hir_owner_node to return an OwnerNode::Item of ItemKind::Mod, or OwnerNode::Crate. Any other node shape triggers this, meaning the LocalModId did not refer to an actual module/crate owner.

Source

Thrown at compiler/rustc_middle/src/hir/map.rs:420

    }

    /// Gets the attributes on the crate. This is preferable to
    /// invoking `krate.attrs` because it registers a tighter
    /// dep-graph access.
    pub fn hir_krate_attrs(self) -> &'tcx [Attribute] {
        self.hir_attrs(CRATE_HIR_ID)
    }

    pub fn hir_rustc_coherence_is_core(self) -> bool {
        find_attr!(self.hir_krate_attrs(), RustcCoherenceIsCore)
    }

    pub fn hir_get_module(self, module: LocalModId) -> (&'tcx Mod<'tcx>, Span, HirId) {
        let hir_id = HirId::make_owner(module.to_local_def_id());
        match self.hir_owner_node(hir_id.owner) {
            OwnerNode::Item(&Item { span, kind: ItemKind::Mod(_, m), .. }) => (m, span, hir_id),
            OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id),
            node => panic!("not a module: {node:?}"),
        }
    }

    /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
    pub fn hir_walk_toplevel_module<V>(self, visitor: &mut V) -> V::Result
    where
        V: Visitor<'tcx>,
    {
        let (top_mod, span, hir_id) = self.hir_get_module(CRATE_MOD_ID);
        visitor.visit_mod(top_mod, span, hir_id)
    }

    /// Walks the attributes in a crate.
    pub fn hir_walk_attributes<V>(self, visitor: &mut V) -> V::Result
    where
        V: Visitor<'tcx>,
    {
        let krate = self.hir_crate_items(());

View on GitHub (pinned to 22057b88b0)

Solutions

  1. If this is your own tool/lint, validate that the LocalModId you pass actually points at a mod owner before calling hir_get_module.
  2. Report as a rustc ICE if reached through normal compilation — include the node printed in the message.
  3. Try a clean build or a different nightly to rule out a stale incremental cache holding a bad HIR.
Defensive patterns

Strategy: type-guard

Validate before calling

// Before treating a HirId as a module, confirm the HIR node kind
// is actually a module item.
use rustc_hir::{HirId, Node, Item, ItemKind};
use rustc_middle::ty::TyCtxt;

fn hir_node_is_module(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
    matches!(
        tcx.hir().get(hir_id),
        Node::Item(Item { kind: ItemKind::Mod(..), .. })
    )
}

Type guard

// Narrow a HirId to a known-module node before calling
// module-specific HIR map methods.
use rustc_hir::{HirId, Node, Item, ItemKind};
use rustc_middle::ty::TyCtxt;

fn as_module_owner<'tcx>(
    tcx: TyCtxt<'tcx>,
    hir_id: HirId,
) -> Option<&'tcx Item<'tcx>> {
    if let Node::Item(item) = tcx.hir().get(hir_id) {
        if matches!(item.kind, ItemKind::Mod(..)) {
            return Some(item);
        }
    }
    None
}

Prevention

When it happens

Trigger: Calling tcx.hir_get_module(id) with a LocalModId whose owning def is not a mod item (e.g. a block expression, an inline module whose owner is a function, or an out-of-range/corrupted LocalModId). Happens inside rustc passes or custom lints/tools that walk module trees.

Common situations: Compiler-internal bug where a non-module owner is registered in the module map; procedural macros or third-party analysis tools that synthesize or pass through HirId/LocalModId values incorrectly; mismatch after a HIR refactor.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/0cbf496d18cf4f32.json. Report an issue: GitHub.