{"record":{"id":"b425434cf34a413c","repo":"aosabook/500lines","slug":"local-variable-s-referenced-before-assignment-b42543","errorCode":null,"errorMessage":"local variable '%s' referenced before assignment","messagePattern":"local variable '(.+?)' referenced before assignment","errorType":"exception","errorClass":"UnboundLocalError","httpStatus":null,"severity":"error","filePath":"interpreter/code/byterun/simple_python_interpreter.py","lineNumber":245,"sourceCode":"        elif name in frame.f_globals:\n            val = frame.f_globals[name]\n        elif name in frame.f_builtins:\n            val = frame.f_builtins[name]\n        else:\n            raise NameError(\"name '%s' is not defined\" % name)\n        self.push(val)\n\n    def byte_STORE_NAME(self, name):\n        self.frame.f_locals[name] = self.pop()\n\n    def byte_DELETE_NAME(self, name):\n        del self.frame.f_locals[name]\n\n    def byte_LOAD_FAST(self, name):\n        if name in self.frame.f_locals:\n            val = self.frame.f_locals[name]\n        else:\n            raise UnboundLocalError(\n                \"local variable '%s' referenced before assignment\" % name\n            )\n        self.push(val)\n\n    def byte_STORE_FAST(self, name):\n        self.frame.f_locals[name] = self.pop()\n\n    def byte_LOAD_GLOBAL(self, name):\n        f = self.frame\n        if name in f.f_globals:\n            val = f.f_globals[name]\n        elif name in f.f_builtins:\n            val = f.f_builtins[name]\n        else:\n            raise NameError(\"global name '%s' is not defined\" % name)\n        self.push(val)\n\n    ## Operators","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/aosabook/500lines/blob/fba689d101eb5600f5c8f4d7fd79912498e950e2/interpreter/code/byterun/simple_python_interpreter.py#L227-L263","documentation":"Raised by byte_LOAD_FAST when a name the compiler classified as a fast local is missing from frame.f_locals at the point of the load. Because a function assigns to the variable somewhere in its body, the compiler made it local and emitted LOAD_FAST/STORE_FAST; the interpreter consults ONLY f_locals (no globals/builtins fallback). This reproduces CPython's UnboundLocalError when a branch reads the local before the assignment runs.","triggerScenarios":"A function that assigns to `name` (forcing LOAD_FAST) but a code path reads `name` before any STORE_FAST runs, e.g. `def f(flag):\\n    if flag: print(x)\\n    x = 1`. Also from augmented assignment or conditional initialization that a skipped branch never executes.","commonSituations":"Adding a later `x = ...` inside a function that silently turns a previously-global `x` into a local; conditional initialization where one branch skips the assignment; refactor that moves an assignment inside an `if`.","solutions":["Initialize the local before any read (assign it at the top of the function or on every branch).","If the global was intended, declare `global name` so the compiler emits LOAD_GLOBAL instead of LOAD_FAST.","Restructure the logic so the STORE_FAST always precedes the LOAD_FAST on every reachable path."],"exampleFix":"// before\ndef f(flag):\n    if flag: print(x)   # UnboundLocalError\n    x = 1\n// after\ndef f(flag):\n    x = 0\n    if flag: print(x)","handlingStrategy":"validation","validationCode":"# static check: every LOAD_FAST name has a STORE_FAST that dominates it\nimport dis\nfast_reads = {i.argval for i in dis.get_instructions(code) if i.opname == 'LOAD_FAST'}\nfast_writes = {i.argval for i in dis.get_instructions(code) if i.opname == 'STORE_FAST'}\nunsafe = fast_reads - fast_writes   # names read but never assigned\n# at runtime, guard the read:\nif name in frame.f_locals:\n    val = frame.f_locals[name]\nelse:\n    val = <default>","typeGuard":null,"tryCatchPattern":"try:\n    interpreter.run_frame(frame)\nexcept UnboundLocalError as e:\n    log.warning('local read before assign: %s', e)","preventionTips":["Initialize locals at the top of every function that conditionally assigns them.","Use `global name` when you intend a module-level binding.","Run a static analyzer (pylint W0612/unbound) to catch read-before-write paths."],"tags":["unbound-local","interpreter","python","scope","bytecode"],"backgroundTag":null,"analyzedSha":"fba689d101eb5600f5c8f4d7fd79912498e950e2","analyzedAt":"2026-08-13T06:26:32.792Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}