facebook/relay · error

Unexpected RelayResolver

Error message

Unexpected RelayResolver

What it means

Internal invariant panic in write_constant_value: a Primitive::RelayResolverModel (a resolver reference) was passed where only printable constant primitives are allowed. Resolver references must be handled by dedicated printer paths, not constant printing.

Source

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

                        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. Ensure resolvers are referenced only from fields/exports, not as literal constant values
  2. Check resolver @exportable/@RelayResolver usage so model references are routed through export paths
  3. File a Relay compiler bug with a minimal repro — this branch should be unreachable in valid schemas
Defensive patterns

Strategy: validation

Validate before calling

// Resolve RelayResolverModel references to their export/field value before printing
let resolved = match primitive {
    Primitive::RelayResolverModel { .. } => resolve_resolver_reference(primitive)?,
    other => other,
};
write_constant_value(&resolved);

Type guard

fn is_literal_primitive(p: &Primitive) -> bool {
    !matches!(p, Primitive::RelayResolverModel { .. })
}

Try / catch

// pre-validate; a panic here is a compiler bug, capture with a repro and report upstream

Prevention

When it happens

Trigger: write_argument_value or write_constant_value receives Primitive::RelayResolverModel — a Relay resolver model value reaching the constant/argument printing branch.

Common situations: A resolver whose return/argument type is another resolver, or a mis-wired resolver schema, causing the codegen printer to treat the resolver reference as a literal.

Related errors


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