UnboundLocalError: cannot access local variable (tested)

UnboundLocalError: cannot access local variable 'x' where it is not associated with a value (before 3.11: local variable 'x' referenced before assignment) means Python treats the name as local and it has no value yet. We measured the three common causes on Python 3.13.5.

The rule

If a function assigns to a name anywhere in its body (=, +=, for x in, import, ...), that name is local for the whole function, decided when the function is compiled. Reading it before the assignment has run raises UnboundLocalError. Python 3.11+ phrases it as cannot access local variable 'x' where it is not associated with a value; older versions said local variable 'x' referenced before assignment (not re-tested here).

1. += on a global

count = 0

def increment():
    count += 1

try:
    increment()
except UnboundLocalError as e:
    print(type(e).__name__ + ":", e)

Output:

UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

Measured on Python 3.13.5: count += 1 both reads and assigns count, so it's local, and the read happens first.

2. An assignment later in the function breaks an earlier read

total = 10

def report():
    print(total)          # fails, though this line comes BEFORE the assignment
    total = 20

try:
    report()
except UnboundLocalError as e:
    print(type(e).__name__ + ":", e)

Output:

UnboundLocalError: cannot access local variable 'total' where it is not associated with a value

Measured: print(total) fails even though it runs before total = 20 and a global total exists. Remove the assignment, rename the local, or declare global.

3. Assigned in only one branch

def status(code):
    if code == 200:
        msg = "ok"
    return msg

print(status(200))
try:
    status(404)
except UnboundLocalError as e:
    print(type(e).__name__ + ":", e)

Output:

ok
UnboundLocalError: cannot access local variable 'msg' where it is not associated with a value

Measured: works for 200, fails for 404, because msg was never set on that path. Give it a default before the if or add an else. Same for variables set only inside try, or only inside a loop that ran zero times.

4. Fixes: global and nonlocal

count = 0

def increment():
    global count
    count += 1

increment(); increment()
print(count)

def make_counter():
    n = 0
    def step():
        nonlocal n
        n += 1
        return n
    return step

step = make_counter()
print(step(), step())

Output:

2
1 2

global for module-level names, nonlocal for a variable in an enclosing function. Often cleaner: pass the value in and return the new value.

Frequently asked questions

What does UnboundLocalError: cannot access local variable mean?

The name is local to the function (it's assigned somewhere in it), but was read before any assignment ran. That's the Python 3.11+ wording, which we measured on 3.13.5.

Why does x += 1 inside a function raise UnboundLocalError?

+= assigns, making x local, then reads it first. We measured it with a global count; add global count, or pass and return the value.

Why do I get UnboundLocalError on a line before the assignment?

Locals are decided for the whole function at compile time. We measured print(total) failing because total = 20 appears later in the same function.

How do I fix UnboundLocalError in an if statement?

Set a default before the if or add an else. We measured a variable set only for code 200 failing for 404.

Written with AI assistance. Measured on 2026-10-09 with Python 3.13.5 on Linux: += on a global, a read before a later assignment, a variable set in one branch only, and the global and nonlocal fixes. Every block was run verbatim and its output pasted from that run. Pre-3.11 wording was not re-tested. PlainHeaders is our extension; everything else here is built-in Python.