facebook/relay · error

@__metadata directive expect only constant argument values.

Error message

@__metadata directive expect only constant argument values.

What it means

The @__metadata directive's single argument value must be a GraphQL constant (string, enum, etc.). build_internal_metadata_directives panics when the value is a variable or other non-constant Value, because metadata must be fully resolvable at compile time.

Source

Thrown at compiler/crates/relay-codegen/src/build_ast.rs:396

    fn array(&mut self, array: Vec<Primitive>) -> AstKey {
        self.ast_builder.intern(Ast::Array(array))
    }

    fn build_internal_metadata_directives(&mut self, directives: &[Directive]) -> Vec<ObjectEntry> {
        directives
            .iter()
            .filter_map(|directive| {
                if directive.name.item == *INTERNAL_METADATA_DIRECTIVE {
                    if directive.arguments.len() != 1 {
                        panic!("@__metadata directive should have only one argument!");
                    }

                    let arg = &directive.arguments[0];
                    let key = arg.name.item;
                    let value = match &arg.value.item {
                        Value::Constant(value) => self.build_constant_value(value),
                        _ => {
                            panic!("@__metadata directive expect only constant argument values.");
                        }
                    };

                    Some(ObjectEntry { key: key.0, value })
                } else {
                    None
                }
            })
            .collect()
    }

    fn use_exec_time_resolvers(&self, context: &ContextualMetadata) -> bool {
        let feature_flags = &self.project_config.feature_flags;
        feature_flags.enable_resolver_normalization_ast
            || (feature_flags.enable_exec_time_resolvers_directive
                && context.has_exec_time_resolvers_directive
                && !context.has_exec_time_resolvers_enabled_provider)
    }

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Replace the variable with a literal constant value in the @__metadata argument.
  2. Regenerate the fragment/operation through the compiler rather than hand-writing metadata.
  3. If tooling generates these directives, fix the generator to emit Value::Constant values only.
  4. Review Relay docs for the exact expected @__metadata argument shape (constant, single argument).

Example fix

// before
fragment FooResolver on Query @__metadata(parentType: $parent) { ... }
// after
fragment FooResolver on Query @__metadata(parentType: "Query") { ... }
Defensive patterns

Strategy: validation

Validate before calling

fn metadata_args_are_constant(d: &Directive) -> bool {
    d.arguments.iter().all(|a| matches!(a.value.item, Value::Constant(_)))
}

Type guard

fn is_constant(v: &Value) -> bool { matches!(v.item, Value::Constant(_)) }

Try / catch

let result = std::panic::catch_unwind(|| build_internal_metadata_directives(&directives));
if result.is_err() { report("@__metadata argument must be a constant value"); }

Prevention

When it happens

Trigger: Writing `@__metadata(parentType: $someVar)` or any variable/inline non-constant value; the match on Value::Constant falls through to the panic arm during build_fragment_metadata or build_request_parameters.

Common situations: Copy-pasting an argument with a variable from an operation into a @__metadata directive; tooling that injects variable references into metadata; misunderstanding that GraphQL variables aren't allowed in compiler-internal directives.

Related errors


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