{"record":{"id":"cc433f3c636efc96","repo":"facebook/relay","slug":"unexpected-storagekey","errorCode":null,"errorMessage":"Unexpected StorageKey","messagePattern":"Unexpected StorageKey","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/crates/relay-codegen/src/printer.rs","lineNumber":930,"sourceCode":"                    f.push('{');\n                    for ObjectEntry { key: name, value } in obj {\n                        write!(f, \"\\\\\\\"{name}\\\\\\\":\")?;\n                        write_constant_value(f, builder, value)?;\n                        f.push(',');\n                    }\n                    if !obj.is_empty() {\n                        f.pop();\n                    }\n                    f.push('}');\n                    Ok(())\n                }\n            }\n        }\n        Primitive::Null | Primitive::SkippableNull => {\n            f.push_str(\"null\");\n            Ok(())\n        }\n        Primitive::StorageKey(_, _) => panic!(\"Unexpected StorageKey\"),\n        Primitive::RawString(_) => panic!(\"Unexpected RawString\"),\n        Primitive::GraphQLModuleDependency(_) => panic!(\"Unexpected GraphQLModuleDependency\"),\n        Primitive::JSModuleDependency { .. } => panic!(\"Unexpected JSModuleDependency\"),\n        Primitive::ResolverModuleReference { .. } => panic!(\"Unexpected ResolverModuleReference\"),\n        Primitive::PropertyAccessor(_) => panic!(\"Unexpected PropertyAccessor\"),\n        Primitive::DynamicImport { .. } => panic!(\"Unexpected DynamicImport\"),\n        Primitive::RelayResolverModel { .. } => panic!(\"Unexpected RelayResolver\"),\n    }\n}\n","sourceCodeStart":912,"sourceCodeEnd":940,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/relay-codegen/src/printer.rs#L912-L940","documentation":"write_constant_value converts a Primitive into the literal JS text of a generated artifact and only handles value kinds valid in a constant position (literals, enums, lists, objects, null). StorageKey primitives are handled elsewhere (storage key generation), so encountering one in a constant position means a StorageKey leaked into argument/value printing; the printer panics rather than emitting wrong code.","triggerScenarios":"Printing a fragment argument or embedded value where a Primitive::StorageKey was produced by the builder — e.g. a @static_arg/storage-key construct nested inside a position printed by write_argument_value → write_constant_value (lists, object fields) rather than the dedicated storage-key path.","commonSituations":"Combining @static_arg/@arguments constructs with positions the constant printer visits (nested lists/objects); custom transforms emitting StorageKey primitives in ordinary argument positions; compiler regression after upgrading Relay.","solutions":["Locate the argument producing the StorageKey (usually @static_arg / @arguments on a fragment spread) and move it to a supported position or use a plain constant value","Remove/replace nested storage-key-producing arguments inside lists or objects printed as constants","Check for custom transforms that inject StorageKey primitives and emit the value directly instead","Update the Relay compiler to a version where StorageKey printing is routed through the storage-key path"],"exampleFix":"// before\n...Frag @static_arg(key: \"inner\", value: [[\"nested\"]])\n// after\n...Frag @static_arg(key: \"inner\", value: \"nested\")","handlingStrategy":"validation","validationCode":"function ensureConstantArgs(doc) {\n  visit(doc, {\n    Argument(node) {\n      if (containsStorageKeyConstruct(node.value)) {\n        throw new Error(`Argument ${node.name.value} must be a plain constant`);\n      }\n    }\n  });\n}","typeGuard":"const isConstantPrimitive = (p) =>\n  ['string','number','boolean','enum','list','object','null'].includes(p.kind);","tryCatchPattern":"try {\n  generateArtifacts();\n} catch (e) {\n  if (String(e).includes('Unexpected StorageKey')) {\n    // move the @static_arg/storage-key usage to a supported position\n  }\n  throw e;\n}","preventionTips":["Use @static_arg only in its documented position on fragment spreads","Never nest storage-key constructs inside lists/objects of other arguments","Keep custom transforms free of StorageKey primitives in argument values","Run codegen in CI so regressions surface early"],"tags":["compiler","codegen","storage-key","primitive"],"backgroundTag":"unexpected-primitive-kind","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}