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

  1. Change the resolver file to use a named export (e.g. `export function myResolver() {...}`) rather than `export default`
  2. Ensure the module reference for the resolver is constructed with ModuleImportName::Named in the transform/printer pipeline
  3. Update the Relay compiler version so resolver module imports are always registered as named imports
  4. 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

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


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