{"record":{"id":"91c3bad5ebb81222","repo":"facebook/relay","slug":"expected-an-object-key-or-null","errorCode":null,"errorMessage":"Expected an object key or null","messagePattern":"Expected an object key or null","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/crates/relay-codegen/src/printer.rs","lineNumber":855,"sourceCode":"            .expect(\"Expected `items` to exist\")\n            .value;\n        let array = builder.lookup(items.assert_key()).assert_array();\n\n        f.push('[');\n        let mut after_first = false;\n        for key_or_null in array {\n            match key_or_null {\n                Primitive::Null => {}\n                Primitive::Key(key) => {\n                    if after_first {\n                        f.push(',');\n                    } else {\n                        after_first = true;\n                    }\n                    let object = builder.lookup(*key).assert_object();\n                    write_argument_value(f, builder, object)?;\n                }\n                _ => panic!(\"Expected an object key or null\"),\n            }\n        }\n        f.push(']');\n    } else {\n        // We filtered out Variables, here it should only be ObjectValue\n        let fields = &arg\n            .iter()\n            .find(|entry| entry.key == CODEGEN_CONSTANTS.fields)\n            .expect(\"Expected `fields` to exist\")\n            .value;\n        let fields = builder.lookup(fields.assert_key()).assert_array();\n\n        f.push('{');\n        for field in fields {\n            let field = builder.lookup(field.assert_key()).assert_object();\n            let name = &field\n                .iter()\n                .find(|entry| entry.key == CODEGEN_CONSTANTS.name)","sourceCodeStart":837,"sourceCodeEnd":873,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/relay-codegen/src/printer.rs#L837-L873","documentation":"write_argument_value serializes constant argument values into the generated artifact. When it encounters a list element that is neither a storage-key object nor null, it panics. Before reaching this branch, Variables and object values are filtered out; the code only supports serializing lists whose items reduce to an object (used for static storage keys) or null, so any other primitive kind inside that list position violates an internal invariant.","triggerScenarios":"Printing an argument value that is a list containing an unexpected element kind at that position — e.g. a variable, scalar, or enum element where the builder expected a nested object (for @static_arg/StorageKey emission) or null; corrupted IR where list item filtering didn't happen as designed.","commonSituations":"Using @static_arg/@arguments with list arguments containing items the codegen cannot reduce; custom transforms injecting non-object list elements into static argument positions; compiler version mismatches producing IR the printer doesn't expect.","solutions":["Simplify the list argument passed to @static_arg/@arguments so its elements are supported (objects or null) — e.g. use plain constant values instead of nested variables","Remove variables from list-typed arguments that feed static storage key generation; hoist them as separate arguments","Verify which fragment/argument triggers it by bisecting documents, and check the IR transform output for that node","Upgrade or fix the compiler so list argument handling in write_static_storage_key matches the emitted IR"],"exampleFix":"// before\nquery($ids: [ID]) @static_arg(key: \"ids\", value: $ids) { ... }\n// after\nquery @static_arg(key: \"ids\", value: [\"123\", \"456\"]) { ... }","handlingStrategy":"validation","validationCode":"function validateStaticArgValue(value) {\n  if (Array.isArray(value)) {\n    return value.every(v => v === null || (v && typeof v === 'object' && !Array.isArray(v)) || validateStaticArgValue(v));\n  }\n  return true;\n}\nif (!validateStaticArgValue(staticArgValue)) throw new Error('static arg list items must be objects or null');","typeGuard":"const isStorageKeyListItem = (v) =>\n  v === null || (typeof v === 'object' && v !== null && !Array.isArray(v));","tryCatchPattern":"try {\n  generateArtifacts();\n} catch (e) {\n  if (String(e).includes('Expected an object key or null')) {\n    // simplify the list argument feeding @static_arg\n  }\n  throw e;\n}","preventionTips":["Keep @static_arg/@arguments values simple and fully constant","Avoid variables inside list arguments used for storage keys","Bisect documents when codegen panics to find the offending argument","Pin and update Relay compiler versions together across the monorepo"],"tags":["compiler","codegen","storage-key","arguments"],"backgroundTag":"invalid-argument-value-kind","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}