{"record":{"id":"91b9bcc8d3a48ed4","repo":"facebook/relay","slug":"node-search-exists","errorCode":null,"errorMessage":"Node.search exists","messagePattern":"Node\\.search exists","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/crates/schema-set/src/build_in_memory_schema.rs","lineNumber":835,"sourceCode":"        let node = schema.object(node_type.get_object_id().expect(\"Node is an object\"));\n\n        // Implemented interfaces resolve in alphabetical name order.\n        let interface_names: Vec<String> = node\n            .interfaces\n            .iter()\n            .map(|id| schema.interface(*id).name.item.to_string())\n            .collect();\n        assert_eq!(interface_names, vec![\"Alpha\", \"Mango\", \"Zeta\"]);\n\n        // Directives applied to the type are sorted by name.\n        let type_directives: Vec<String> =\n            node.directives.iter().map(|d| d.name.to_string()).collect();\n        assert_eq!(type_directives, vec![\"abc\", \"zed\"]);\n\n        let search = schema.field(\n            schema\n                .named_field(node_type, \"search\".intern())\n                .expect(\"Node.search exists\"),\n        );\n\n        // Field arguments are sorted by name.\n        let argument_names: Vec<String> = search\n            .arguments\n            .iter()\n            .map(|arg| arg.name.item.to_string())\n            .collect();\n        assert_eq!(argument_names, vec![\"alpha\", \"mango\", \"zebra\"]);\n\n        // Directives applied to the field are sorted by name too.\n        let field_directives: Vec<String> = search\n            .directives\n            .iter()\n            .map(|d| d.name.to_string())\n            .collect();\n        assert_eq!(field_directives, vec![\"abc\", \"zed\"]);\n    }","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/schema-set/src/build_in_memory_schema.rs#L817-L853","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","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.","If the field was intentionally removed, delete or rewrite the assertion to target a field that still exists."],"exampleFix":"// before\nlet search = schema.field(\n    schema\n        .named_field(node_type, \"search\".intern())\n        .expect(\"Node.search exists\"),\n);\n// after\nlet field_id = schema\n    .named_field(node_type, \"search\".intern())\n    .unwrap_or_else(|| panic!(\"Node.search missing; Node fields: {:?}\", node.fields));\nlet search = schema.field(field_id);","handlingStrategy":"type-guard","validationCode":"// Before relying on a field lookup, assert presence:\nassert!(\n    schema.named_field(node_type, \"search\".intern()).is_some(),\n    \"Node must declare a `search` field\"\n);","typeGuard":"fn has_field(schema: &Schema, type_: TypeRef, name: &str) -> bool {\n    schema.named_field(type_, name.intern()).is_some()\n}","tryCatchPattern":"// Rust panics cannot be caught with try/catch; avoid .expect on fallible lookups:\nmatch schema.named_field(node_type, \"search\".intern()) {\n    Some(id) => process(schema.field(id)),\n    None => eprintln!(\"field `search` not found on type\"),\n}\n// (std::panic::catch_unwind only as a last resort in test harnesses)","preventionTips":["Never `.expect`/`.unwrap` on Option-returning schema lookups in library or test code without embedding context in the message.","Keep the SDL fixture and the looked-up names in the same test function and derive one from the other when possible.","After changing any SDL string in a test, grep the test for `.expect` messages tied to old names.","Check `get_type`/`object` results before field lookups so failures localize to the actual broken step."],"tags":["rust","panic","graphql-schema","test-assertion"],"backgroundTag":"expect-panic-not-found","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}