{"record":{"id":"ce2306f04372f52f","repo":"pardeike/Harmony","slug":"variablestate-variable-of-type-type-not-found","errorCode":null,"errorMessage":"VariableState: variable of type {type} not found","messagePattern":"VariableState: variable of type (.+?) not found","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Internal/VariableState.cs","lineNumber":24,"sourceCode":"{\r\n\tinternal class VariableState\r\n\t{\r\n\t\treadonly Dictionary<InjectionType, LocalBuilder> injected = [];\r\n\t\treadonly Dictionary<string, LocalBuilder> other = [];\r\n\r\n\t\tpublic void Add(InjectionType type, LocalBuilder local) => injected[type] = local;\r\n\t\tpublic void Add(string name, LocalBuilder local) => other[name] = local;\r\n\r\n\t\tpublic bool TryGetValue(InjectionType type, out LocalBuilder local) => injected.TryGetValue(type, out local);\r\n\t\tpublic bool TryGetValue(string name, out LocalBuilder local) => other.TryGetValue(name, out local);\r\n\r\n\t\tpublic LocalBuilder this[InjectionType type]\r\n\t\t{\r\n\t\t\tget\r\n\t\t\t{\r\n\t\t\t\tif (injected.TryGetValue(type, out var local))\r\n\t\t\t\t\treturn local;\r\n\t\t\t\tthrow new ArgumentException($\"VariableState: variable of type {type} not found\");\r\n\t\t\t}\r\n\t\t\tset => injected[type] = value;\r\n\t\t}\r\n\r\n\t\tpublic LocalBuilder this[string name]\r\n\t\t{\r\n\t\t\tget\r\n\t\t\t{\r\n\t\t\t\tif (other.TryGetValue(name, out var local))\r\n\t\t\t\t\treturn local;\r\n\t\t\t\tthrow new ArgumentException($\"VariableState: variable named '{name}' not found\");\r\n\t\t\t}\r\n\t\t\tset => other[name] = value;\r\n\t\t}\r\n\t}\r\n}\r\n","sourceCodeStart":6,"sourceCodeEnd":41,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Internal/VariableState.cs#L6-L41","documentation":"VariableState tracks local variables injected during transpiler/emitter workflows, keyed by InjectionType. This indexer getter throws ArgumentException when no LocalBuilder was previously registered under the requested type key.","triggerScenarios":"Querying state[SomeInjectionType] (e.g. state[InjectionType.CurrentMethod] or similar) in an emitter/transpiler helper before anything has stored a LocalBuilder for that InjectionType key.","commonSituations":"A transpiler registered extra variables under one injection type but reads them under another; two transpilers assume each other populated the state; refactor renamed an InjectionType so the store call no longer matches the lookup.","solutions":["Store the variable first (state[type] = localBuilder) before reading it","Use TryGetValue-style logic via the underlying dictionary or check injected state before indexing","Log/dump the currently registered InjectionType keys to spot the key mismatch"],"exampleFix":"// before\nvar method = state[InjectionType.CurrentMethod];\n// after\nvar local = state.TryGet(InjectionType.CurrentMethod, out var l) ? l : throw new InvalidOperationException(\"Run InjectVariable first\");","handlingStrategy":"validation","validationCode":"if (!state.InjectedTypes.Contains(type)) throw new InvalidOperationException($\"{type} not injected yet\");\nvar local = state[type];","typeGuard":null,"tryCatchPattern":"try { local = state[type]; } catch (ArgumentException) { local = il.DeclareLocal(expectedType); state[type] = local; }","preventionTips":["Register every InjectionType key immediately before or during emission","Centralize key names in constants shared by storing and reading code","Unit-test transpilers end-to-end so missing registrations surface"],"tags":["transpiler","emitting","locals","csharp"],"backgroundTag":"record-not-found","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}