facebook/relay · error
Expected a named import for Relay Resolvers
Error message
Expected a named import for Relay Resolvers
What it means
When printing a Relay Resolver field that references a resolver module, the printer must emit a named module import. A default import (ModuleImportName::Default) is invalid for Relay Resolvers, so the printer panics. The named-import requirement exists because generated code accesses the resolver by `resolverFunctionName` and the import machinery only tracks named bindings for these modules.
Source
Thrown at compiler/crates/relay-codegen/src/printer.rs:656
} => self.write_relay_resolver_model(
f,
*graphql_module_name,
*graphql_module_path,
resolver_fn,
injected_field_name_details.as_ref().copied(),
),
}
}
fn write_resolver_module_reference(
&mut self,
f: &mut String,
resolver_function_name: ModuleImportName,
field_type: &StringKey,
) -> FmtResult {
match resolver_function_name {
ModuleImportName::Default(_) => {
panic!("Expected a named import for Relay Resolvers")
}
ModuleImportName::Named { name, .. } => {
write!(
f,
"{{ resolverFunctionName: \"{name}\", fieldType: \"{field_type}\" }}"
)
}
}
}
fn write_js_dependency(
&mut self,
f: &mut String,
module_import_name: ModuleImportName,
path: Cow<'_, str>,
) -> FmtResult {
if self.eager_es_modules {
let path = path.into_owned();View on GitHub (pinned to 668b1b85e0)
Solutions
- Change the resolver file to use a named export (e.g. `export function myResolver() {...}`) rather than `export default`
- Ensure the module reference for the resolver is constructed with ModuleImportName::Named in the transform/printer pipeline
- Update the Relay compiler version so resolver module imports are always registered as named imports
- If using custom IR transforms, fix the pass that lowers resolver references so it never produces Default import names
Example fix
// before
export default function userName(root) { return root.name; }
// after
export function userName(root) { return root.name; } Defensive patterns
Strategy: validation
Validate before calling
// Ensure resolver files use named exports, not default exports:
const src = fs.readFileSync(resolverPath, 'utf8');
if (/export\s+default/.test(src)) {
throw new Error(`Relay Resolver ${resolverPath} must use named exports, not default`);
} Type guard
const isNamedImport = (imp) => imp != null && imp.type === 'named';
Try / catch
try {
generateArtifacts();
} catch (e) {
if (String(e).includes('Expected a named import for Relay Resolvers')) {
// convert resolver default exports to named exports
}
throw e;
} Prevention
- Use named exports for all Relay Resolver functions
- Never map resolver modules to default imports in custom transforms
- Keep the compiler and relay runtime packages in sync
- Codegen custom transforms should always construct ModuleImportName::Named for resolvers
When it happens
Trigger: Printing a ResolverModuleReference primitive whose module import was registered as a default import instead of a named import; a resolver field definition (e.g. `export default function ...` in a Relay Resolver file, or module config mapping the resolver as default) reaching write_resolver_module_reference during codegen.
Common situations: Writing a Relay Resolver file using `export default` instead of a named export; custom codegen/transform that builds a ModuleImportName::Default for resolver modules; misconfigured artifact generation for Relay Resolvers.
Related errors
- Unexpected ResolverModuleReference
- Expected Condition with static value to have been pruned or
- @module fragments should be named 'FragmentName_propName', g
- Expected an object key or null
- Unexpected StorageKey
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/5c74151a47bf343b.
Report an issue: GitHub.