facebook/relay · error
Expect the module import inline fragment to have a type
Error message
Expect the module import inline fragment to have a type
What it means
split_module_import's transform_inline_fragment only processes inline fragments identified as module imports; after confirming it is one, it force-unwraps the fragment's type_condition. The expect fires when a module-import inline fragment has no type condition (e.g. ... @module { ... } with no 'on Type'), since the split/normalization operation requires it.
Source
Thrown at compiler/crates/relay-transforms/src/match_/split_module_import.rs:114
}
}
fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
if let Some(module_metadata) = self.inline_module_metadata(fragment) {
// We do not need to write normalization files for base fragments.
// This is because when we process the base project, the normalization fragment will
// be written, and we do not want to emit multiple normalization fragments with
// the same name. If we did, Haste would complain about a duplicate module definition.
if self
.base_fragment_names
.contains(&module_metadata.fragment_name)
{
return self.default_transform_inline_fragment(fragment);
}
let parent_type = fragment
.type_condition
.expect("Expect the module import inline fragment to have a type");
let normalization_name =
get_normalization_operation_name(module_metadata.fragment_name.0).intern();
let schema = &self.program.schema;
let created_split_operation = self
.split_operations
.entry(normalization_name)
.or_insert_with(|| {
// Exclude `__module_operation/__module_component: js` field selections from `SplitOperation`
let next_selections = fragment
.selections
.iter()
.filter(|selection| match selection {
Selection::ScalarField(field) => {
field.alias.is_none()
|| schema.field(field.definition.item).name.item
!= MATCH_CONSTANTS.js_field_name
}View on GitHub (pinned to 668b1b85e0)
Solutions
- Add an explicit type condition to the module import inline fragment: ... on TypeName @module(name: "...") { ... }.
- Fix the generator/transform that produced the fragment so it always emits a type condition.
- Confirm the fragment really is a module import — plain inline fragments without a type condition safely take the default_transform_inline_fragment path.
- Re-run codegen after fixing so the split operations are regenerated.
- If the syntax looks valid, minimize the document and report a relay-compiler issue.
Example fix
// before
fragment F on Query {
... @module(name: "ProfilePhoto") { photo }
}
// after
fragment F on Query {
... on User @module(name: "ProfilePhoto") { photo }
} Defensive patterns
Strategy: type-guard
Validate before calling
function validateModuleImportFragment(fragment) {
if (!hasModuleDirective(fragment)) return true;
return Boolean(
fragment.typeCondition && fragment.typeCondition.name?.value
);
}
// before compiling: if (!validateModuleImportFragment(frag)) throw new Error('@module inline fragment needs "on Type"'); Type guard
function hasTypeCondition(fragment) {
return fragment.kind === 'InlineFragment' &&
fragment.typeCondition != null &&
typeof fragment.typeCondition.name?.value === 'string';
} Try / catch
try {
program = applySplitModuleImport(program);
} catch (e) {
if (String(e.message).includes('module import inline fragment to have a type')) {
reportDocumentError(programName, 'Module-import inline fragment is missing its "on TypeName" condition');
}
throw e;
} Prevention
- Always write ... on TypeName @module(name: "...") — never a bare ... @module.
- Add a lint rule requiring typeCondition on inline fragments carrying @module.
- Fix generators/plugins to emit type conditions for module-import fragments.
- Re-run codegen after any fragment refactor so split operations stay in sync.
When it happens
Trigger: An inline fragment annotated for module import (matched via module_metadata) lacking a type condition, so fragment.type_condition is None when computing get_normalization_operation_name and building the split operation.
Common situations: Hand-written fragments using ... @module without 'on Type'; a code generator that dropped the type condition; refactors removing the type condition assuming it can be inferred from the parent type; plugins emitting typeless inline fragments.
Related errors
- Unexpected custom directives: {:#?}
- expected to find a supported argument as checked before
- Cannot have @module selections at multiple paths unless the
- unexpected value for @defer if argument: {other:?}
- unexpected value for @stream if argument: {other:?}
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/764d8e90eed55a4b.
Report an issue: GitHub.