facebook/relay · error

Expected @{} directive to have an export_name argument

Error message

Expected @{} directive to have an export_name argument

What it means

Companion to the path-argument panic: when the custom scalar directive is present, its export_name argument (the exported JS type's name) is mandatory. If arguments.named(EXPORT_NAME_CUSTOM_SCALAR_ARGUMENT_NAME) returns None, the compiler panics instead of generating broken output.

Source

Thrown at compiler/crates/relay-typegen/src/visit.rs:2315

                panic!(
                    "Expected @{} directive to have a path argument",
                    *CUSTOM_SCALAR_DIRECTIVE_NAME
                )
            })
            .expect_string_literal();

        let import_path = typegen_context.project_config.js_module_import_identifier(
            &typegen_context
                .project_config
                .artifact_path_for_definition(typegen_context.definition_source_location),
            &PathBuf::from(path.lookup()),
        );

        let export_name = directive
            .arguments
            .named(ArgumentName(*EXPORT_NAME_CUSTOM_SCALAR_ARGUMENT_NAME))
            .unwrap_or_else(|| {
                panic!(
                    "Expected @{} directive to have an export_name argument",
                    *CUSTOM_SCALAR_DIRECTIVE_NAME
                )
            })
            .expect_string_literal();
        custom_scalars.insert((export_name, PathBuf::from(import_path.lookup())));
        return AST::RawType(export_name);
    }
    // TODO: We could implement custom variables that are provided via the
    // config by inserting them into the schema with directives, thus avoiding
    // having two different ways to express typed custom scalars internally.
    if let Some(custom_scalar) = typegen_context
        .project_config
        .typegen_config
        .custom_scalar_types
        .get(&scalar_name.item)
    {
        match custom_scalar {

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Add the export_name argument naming the exported JS type for the scalar.
  2. Verify the argument spelling matches the compiler constant (export_name).
  3. Keep path and export_name always supplied together in the directive.
  4. Update the emitting tool to a version that always writes both arguments.

Example fix

// before
@customScalar(path: "./src/types/MyScalarType.ts")
// after
@customScalar(path: "./src/types/MyScalarType.ts", export_name: "MyScalarType")
Defensive patterns

Strategy: validation

Validate before calling

if (hasCustomScalarDirective(node) && !getArg(node, 'export_name')) throw new Error('custom scalar directive requires an export_name argument');

Type guard

function hasExportNameArg(directive) { return directive.arguments?.some(a => a.name.value === 'export_name'); }

Prevention

When it happens

Trigger: transform_graphql_scalar_type encounters a custom scalar directive that has a path argument but no export_name argument while generating type information.

Common situations: Partially written annotations; refactors that removed export_name; hand-edited generated/introspection data; tooling that only emits one of the two required arguments.

Related errors


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