facebook/relay · error

@module fragments should be named 'FragmentName_propName', g

Error message

@module fragments should be named 'FragmentName_propName', got '{fragment_name}'.

What it means

Relay's @module directive (used with @match) requires the generated fragment to be named 'FragmentName_propName' so the builder can split the name on the first underscore to recover the property name and the fragment spread. A fragment name with no underscore cannot be decomposed, so codegen panics instead of emitting a module. This is a naming-contract enforcement for @module/@match serialization.

Source

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

        let artifact_path = self
            .project_config
            .artifact_path_for_definition(self.definition_source_location);
        let norm_artifact_path = self
            .project_config
            .path_for_language_specific_artifact(fragment_source_location, normalization_filename);
        self.project_config
            .js_module_import_identifier(&artifact_path, &norm_artifact_path)
    }

    fn build_module_import_selections(
        &mut self,
        module_metadata: &ModuleMetadata,
        inline_fragment: &InlineFragment,
    ) -> Vec<Primitive> {
        let fragment_name = module_metadata.fragment_name;
        let fragment_name_str = fragment_name.0.lookup();
        let underscore_idx = fragment_name_str.find('_').unwrap_or_else(|| {
            panic!(
                "@module fragments should be named 'FragmentName_propName', got '{fragment_name}'."
            )
        });

        let frag_spread = inline_fragment.selections.iter().find_map(|sel| match sel {
            Selection::FragmentSpread(frag_spread) => Some(frag_spread),
            _ => None,
        });
        let args = if let Some(frag_spread) = frag_spread {
            self.build_arguments(&frag_spread.arguments)
        } else {
            None
        };
        let mut module_import = object! {
            args: match args {
                None => Primitive::SkippableNull,
                Some(key) => Primitive::Key(key),
            },

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Rename the module fragment to include the property suffix, e.g. `AvatarFragment_user` where `user` is the property the module populates
  2. Ensure the fragment name referenced by @module `as:` matches `<FragmentName>_<propName>` with at least one underscore
  3. Check the inline fragment selections spread a fragment whose name follows the same convention
  4. Update @match usages generated by older tooling to the current naming convention

Example fix

// before
fragment AvatarFragment on User @module(as: "AvatarFragment") { ... }
// after
fragment AvatarFragment_user on User @module(as: "AvatarFragment_user") { ... }
Defensive patterns

Strategy: validation

Validate before calling

function isValidModuleFragmentName(name) {
  return typeof name === 'string' && name.includes('_') && /^FragmentName_propName$/.test(name.replace(/^[^_]+_[^_]+$/, 'FragmentName_propName'));
}
if (!isValidModuleFragmentName(fragmentName)) {
  throw new Error(`@module fragment must be named 'FragmentName_propName', got '${fragmentName}'`);
}

Type guard

const isModuleFragmentName = (name) =>
  typeof name === 'string' && name.indexOf('_') !== -1;

Try / catch

try {
  compiled = compile(queryText);
} catch (e) {
  if (String(e).includes("@module fragments should be named")) {
    // fix the fragment name to 'FragmentName_propName'
  }
  throw e;
}

Prevention

When it happens

Trigger: Using @module on an inline fragment whose associated fragment name lacks an underscore, e.g. `... on Post @module(as: "UserFragment")` or naming the fragment without the `_propName` suffix (e.g. `AvatarFragment` instead of `AvatarFragment_user`).

Common situations: Developers adopting @match/@module for the first time and naming fragments per ordinary conventions; renaming a module fragment without keeping the `FragmentName_propName` suffix; codegen after upgrading Relay that now enforces the stricter contract.

Related errors


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