facebook/relay · error

Unexpected GraphQLModuleDependency

Error message

Unexpected GraphQLModuleDependency

What it means

Primitive::GraphQLModuleDependency wraps a @module/@match module dependency and is consumed by dedicated module-import writers, not by write_constant_value. If such a dependency appears where a plain constant value is being printed (argument literals, lists, object values), the printer panics because it cannot serialize a module reference as a literal.

Source

Thrown at compiler/crates/relay-codegen/src/printer.rs:932

                        write!(f, "\\\"{name}\\\":")?;
                        write_constant_value(f, builder, value)?;
                        f.push(',');
                    }
                    if !obj.is_empty() {
                        f.pop();
                    }
                    f.push('}');
                    Ok(())
                }
            }
        }
        Primitive::Null | Primitive::SkippableNull => {
            f.push_str("null");
            Ok(())
        }
        Primitive::StorageKey(_, _) => panic!("Unexpected StorageKey"),
        Primitive::RawString(_) => panic!("Unexpected RawString"),
        Primitive::GraphQLModuleDependency(_) => panic!("Unexpected GraphQLModuleDependency"),
        Primitive::JSModuleDependency { .. } => panic!("Unexpected JSModuleDependency"),
        Primitive::ResolverModuleReference { .. } => panic!("Unexpected ResolverModuleReference"),
        Primitive::PropertyAccessor(_) => panic!("Unexpected PropertyAccessor"),
        Primitive::DynamicImport { .. } => panic!("Unexpected DynamicImport"),
        Primitive::RelayResolverModel { .. } => panic!("Unexpected RelayResolver"),
    }
}

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Move the @module usage to the selection position (an inline fragment with @module spreading the module fragment) instead of an argument
  2. Ensure arguments only contain literal values; module references must go through the module import path (write_module_import) not write_constant_value
  3. Audit custom transforms that place GraphQLModuleDependency primitives in argument values and remove them
  4. Update Relay compiler if the IR no longer matches what the printer expects

Example fix

// before
... on Post @module(as: "User_post") { arg: someModule }
// after
... on Post @module(as: "User_post") { someField }  // module spreads as selections, not arguments
Defensive patterns

Strategy: validation

Validate before calling

function assertNoModuleDepsInArgs(doc) {
  visit(doc, {
    Argument(node) {
      if (referencesModuleDirective(node.value)) {
        throw new Error(`Module dependencies cannot be used in argument '${node.name.value}'`);
      }
    }
  });
}

Type guard

const isModuleRef = (v) => typeof v === 'string' && v.includes('@module');

Try / catch

try {
  generateArtifacts();
} catch (e) {
  if (String(e).includes('Unexpected GraphQLModuleDependency')) {
    // move the @module usage from arguments into selections
  }
  throw e;
}

Prevention

When it happens

Trigger: A @module/@match-produced GraphQLModuleDependency primitive flowing into an argument value or constant position — e.g. using a module fragment spread/dependency as (or inside) a printed argument rather than as a selection.

Common situations: Misusing @module/@match so the module dependency lands in an argument instead of a selection; custom transforms building module dependencies inside argument values; upgrading the compiler and old IR shapes now reaching write_constant_value.

Related errors


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