facebook/relay · error

Expected an IR that models a type

Error message

Expected an IR that models a type

What it means

expect_type_ir unwraps a DocblockIr and panics unless it is the Type variant. A docblock (e.g. @RelayResolver type doc) that should describe a GraphQL type produced a different IR (field or other), meaning the docblock was parsed/classified unexpectedly.

Source

Thrown at compiler/crates/relay-compiler/src/build_project/build_resolvers_schema/extract_docblock_ir.rs:161

            .map(|docblock_ir| {
                let ir = expect_type_ir(docblock_ir);
                AllocatedDocblockIr { ir, is_base }
            })
            .collect(),
        field_irs: field_irs
            .into_iter()
            .map(|docblock_ir| {
                let ir = expect_field_ir(docblock_ir);
                AllocatedDocblockIr { ir, is_base }
            })
            .collect(),
    })
}

fn expect_type_ir(docblock_ir: relay_docblock::DocblockIr) -> ResolverTypeDocblockIr {
    match docblock_ir {
        DocblockIr::Type(ir) => ir,
        _ => panic!("Expected an IR that models a type"),
    }
}

fn expect_field_ir(docblock_ir: relay_docblock::DocblockIr) -> ResolverFieldDocblockIr {
    match docblock_ir {
        DocblockIr::Field(ir) => ir,
        _ => panic!("Expected an IR that models a field"),
    }
}

struct ResolverSchemaDocuments<'a> {
    type_asts: TypeAsts,
    field_asts_and_definitions: FieldAstsAndDefinitions<'a>,
}
struct TypeAsts(Vec<DocblockAST>);
struct FieldAstsAndDefinitions<'a>(
    FxHashMap<&'a PathBuf, (Vec<DocblockAST>, Option<&'a Vec<ExecutableDefinition>>)>,
);

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Move the docblock to the correct declaration (type-level vs field-level)
  2. Check the docblock directive tags (@RelayResolver vs field tags) match what the declaration models
  3. Fix syntax that makes the docblock parser classify it as a field IR instead of a type IR
Defensive patterns

Strategy: type-guard

Validate before calling

// Before unwrapping, check the variant
if let DocblockIr::Type(_) = docblock_ir {
    let type_ir = expect_type_ir(docblock_ir);
}

Type guard

fn as_type_ir(ir: DocblockIr) -> Option<ResolverTypeDocblockIr> {
    match ir {
        DocblockIr::Type(t) => Some(t),
        _ => None,
    }
}

Try / catch

// not catchable; use as_type_ir and emit a compiler diagnostic instead of unwrapping

Prevention

When it happens

Trigger: ExtractedDocblockIr processes a docblock expected to define or extend a type (e.g. from @RelayResolver on a type-level docblock) but the docblock compiles to DocblockIr::Field or another variant.

Common situations: Misplaced docblock — a field-level docblock where a type docblock is expected, or an @RelayResolver docblock attached to the wrong kind of definition in a resolver file.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/e0eb52cc9b201ede. Report an issue: GitHub.