facebook/relay · error

Unexpected DynamicImport

Error message

Unexpected DynamicImport

What it means

This is an internal compiler invariant panic in write_constant_value. The printer encountered a Primitive::DynamicImport where the schema only allows true constant values (strings, booleans, enums, etc.). DynamicImport primitives are only valid in resolver export positions, never as an argument or constant.

Source

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

                    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. Check whether the resolver/JS module import is used in a position requiring a literal constant and move it to a valid export/dependency position
  2. Verify your resolver type annotations so @module/dynamic imports are not inferred as constants
  3. Reproduce with a minimal schema and file an issue against the Relay compiler (likely a codegen bug)
Defensive patterns

Strategy: validation

Validate before calling

// Rust caller: ensure the primitive is a printable constant before printing
match primitive {
    Primitive::DynamicImport { .. } => panic/handle: route dynamic imports to the module/export printer path instead,
    _ => write_constant_value(primitive),
}

Type guard

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

Try / catch

// panics are not catchable idiomatically; pre-validate with is_constant_printable before calling

Prevention

When it happens

Trigger: Calling write_argument_value or write_constant_value with a Primitive::DynamicImport node — i.e. a schema/resolver value that resolved to a dynamic import reaching the constant-printing path.

Common situations: A Relay resolver or module dependency (@module) incorrectly typed/positioned so a dynamic import is treated as a literal constant during codegen; usually a compiler bug or malformed resolver definition.

Related errors


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