facebook/relay · error

Expected @ directive to have a path argument

Error message

Expected @{} directive to have a path argument

What it means

During typegen, transform_graphql_scalar_type processes fields annotated with a custom scalar directive. When the directive is present but lacks the required path argument (the import path of the JS type module), the compiler panics — the @customScalar directive contract requires both path and export_name.

Solutions

  1. Add the path argument to the custom scalar directive pointing at the module exporting the JS type.
  2. Ensure both path and export_name arguments are present together.
  3. Regenerate the annotation with a current version of the tooling.
  4. Check the expected argument name matches PATH_CUSTOM_SCALAR_ARGUMENT_NAME (exact spelling).

Example fix

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

Strategy: validation

Validate before calling

// validate custom scalar annotations have both path and export_name
if (hasCustomScalarDirective(node) && !getArg(node, 'path')) throw new Error('custom scalar directive requires a path argument');

Type guard

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

Prevention

When it happens

Trigger: A @customScalar (CUSTOM_SCALAR_DIRECTIVE_NAME) annotation applied without a path argument, encountered while transforming scalar types in visit.rs during typegen.

Common situations: Hand-written or tool-generated scalar annotations missing the path argument; renaming/refactoring that dropped the argument; inconsistent versions between the tool emitting the directive and the compiler.

Related errors


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

Appendix: source

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

    }
}

fn transform_graphql_scalar_type(
    typegen_context: &'_ TypegenContext<'_>,
    scalar: ScalarID,
    custom_scalars: &mut CustomScalarsImports,
) -> AST {
    let scalar_definition = typegen_context.schema.scalar(scalar);
    let scalar_name = scalar_definition.name;
    if let Some(directive) = scalar_definition
        .directives
        .named(DirectiveName(*CUSTOM_SCALAR_DIRECTIVE_NAME))
    {
        let path = directive
            .arguments
            .named(ArgumentName(*PATH_CUSTOM_SCALAR_ARGUMENT_NAME))
            .unwrap_or_else(|| {
                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!(

View on GitHub (pinned to 668b1b85e0)