facebook/relay · error

Node.search exists

Error message

Node.search exists

What it means

This is a Rust panic from `.expect("Node.search exists")` in the test `sorts_arguments_interfaces_and_directives_alphabetically` (compiler/crates/schema-set/src/build_in_memory_schema.rs:835). It fires when `schema.named_field(node_type, "search".intern())` returns None, meaning the in-memory schema built from the SDL does not expose a field named `search` on the `Node` object. The library throws it because the test treats a missing field as unrecoverable: without the field there is nothing to sort arguments/directives for. In production code the same lookup API returns an Option/Result that callers must handle.

Source

Thrown at compiler/crates/schema-set/src/build_in_memory_schema.rs:835

        let node = schema.object(node_type.get_object_id().expect("Node is an object"));

        // Implemented interfaces resolve in alphabetical name order.
        let interface_names: Vec<String> = node
            .interfaces
            .iter()
            .map(|id| schema.interface(*id).name.item.to_string())
            .collect();
        assert_eq!(interface_names, vec!["Alpha", "Mango", "Zeta"]);

        // Directives applied to the type are sorted by name.
        let type_directives: Vec<String> =
            node.directives.iter().map(|d| d.name.to_string()).collect();
        assert_eq!(type_directives, vec!["abc", "zed"]);

        let search = schema.field(
            schema
                .named_field(node_type, "search".intern())
                .expect("Node.search exists"),
        );

        // Field arguments are sorted by name.
        let argument_names: Vec<String> = search
            .arguments
            .iter()
            .map(|arg| arg.name.item.to_string())
            .collect();
        assert_eq!(argument_names, vec!["alpha", "mango", "zebra"]);

        // Directives applied to the field are sorted by name too.
        let field_directives: Vec<String> = search
            .directives
            .iter()
            .map(|d| d.name.to_string())
            .collect();
        assert_eq!(field_directives, vec!["abc", "zed"]);
    }

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Confirm the SDL in the test still declares `search(...)` on `type Node` (line ~810 of build_in_memory_schema.rs) and that spelling matches the lookup string exactly.
  2. Replace the `.expect(...)` with proper handling (`if let Some(id) = schema.named_field(...)` or `.ok_or_else(|| ...)?`) so a missing field produces a descriptive error instead of a bare panic message.
  3. Check `build_in_memory_schema`'s field-registration path for regressions that drop fields, and verify `schema.get_type("Node")` / `object(...)` return the type you expect before the lookup.
  4. If the field was intentionally removed, delete or rewrite the assertion to target a field that still exists.

Example fix

// before
let search = schema.field(
    schema
        .named_field(node_type, "search".intern())
        .expect("Node.search exists"),
);
// after
let field_id = schema
    .named_field(node_type, "search".intern())
    .unwrap_or_else(|| panic!("Node.search missing; Node fields: {:?}", node.fields));
let search = schema.field(field_id);
Defensive patterns

Strategy: type-guard

Validate before calling

// Before relying on a field lookup, assert presence:
assert!(
    schema.named_field(node_type, "search".intern()).is_some(),
    "Node must declare a `search` field"
);

Type guard

fn has_field(schema: &Schema, type_: TypeRef, name: &str) -> bool {
    schema.named_field(type_, name.intern()).is_some()
}

Try / catch

// Rust panics cannot be caught with try/catch; avoid .expect on fallible lookups:
match schema.named_field(node_type, "search".intern()) {
    Some(id) => process(schema.field(id)),
    None => eprintln!("field `search` not found on type"),
}
// (std::panic::catch_unwind only as a last resort in test harnesses)

Prevention

When it happens

Trigger: Calling `schema.named_field(object_type, name)` where the object type has no field with that exact interned name. In this test's context it means `build_in_memory_schema` dropped or failed to register the `search(zebra: Int, alpha: Int, mango: Int): String` field declared on `type Node` in the SDL, e.g. the field was never added, was added to a different type, or the SDL text was edited/renamed without updating the test.

Common situations: Renaming or removing the `search` field in the test SDL while the assertion still looks it up; a regression in the in-memory schema builder that silently drops fields; interning the name with the wrong string ("Search" vs "search"); passing a type handle for a different object than the one declaring the field.

Related errors


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