
Encountering a NameError related to a free variable can be quite daunting. This is a scarier version of the <a href="https://pythonprohub.com/python-errors/unboundlocalerror-local-variable-referenced-before-assignment/">UnboundLocalError</a> we saw earlier. It happens specifically when dealing with nested functions (a function inside another function).
⚡ Quick Fix: NameError: free variable ‘x’ referenced before assignment in enclosing scope — Python nonlocal Keyword Fix for Nested Functions
Python saw x += 1 inside your inner function, classified x as a local variable, then crashed because no local x exists yet — the x you meant lives in the outer function’s scope.
# WRONG — inner function tries to modify outer function's variable without declaring it
def outer():
x = 10
def inner():
x += 1 # NameError: free variable 'x' referenced before assignment
print(x)
inner()
outer()
# RIGHT — nonlocal tells Python: use the x from the enclosing outer function
def outer():
x = 10
def inner():
nonlocal x # x now points at outer()'s x, not a new local variable
x += 1
print(x)
inner()
outer() # Output: 11The breakdown below explains exactly why Python makes this classification decision and when nonlocal is the right fix versus returning a value instead.
The Scenario
You have an outer function with a variable, and an inner function tries to change it.
Problem Code:
def outer():
x = 10
def inner():
# We try to change 'x' from the outer scope
x += 1
print(x)
inner()
outer()
# CRASH! NameError: free variable 'x' referenced before assignment...The Fix: nonlocal
Just like we used global to fix scope issues at the top level, we use nonlocal to fix them in nested functions. It tells Python: “I don’t want a new local variable; I want the one from the outer (non-global) scope.”
def outer():
x = 10
def inner():
nonlocal x # <--- The magic fix
x += 1
print(x)
inner()
outer()
# Output: 11 (Success!)NameError: free variable ‘x’ referenced before assignment in enclosing scope — The nonlocal Rule for Nested Functions
NameError: free variable ‘x’ referenced before assignment in enclosing scope fires for the same reason as UnboundLocalError — Python spots an assignment to x inside the inner function and marks it as local for the entire function. The read on x += 1 happens before the assignment completes, and Python crashes.
nonlocal fixes this in one line. Place nonlocal x at the top of the inner function before any reference to x. Python stops treating x as a new local variable and links it directly to the outer function’s x. Every read and write in the inner function now targets the outer scope’s value.
Know the three scope keywords and when each applies.
global targets a module-level variable from inside any function. Use it when you need to modify a variable defined at the top of the file.
nonlocal targets a variable in the nearest enclosing function scope — not global, not local. Use it exclusively inside nested functions and closures.
Neither keyword is needed for reading. Python reads outer scope variables without any declaration — the error only fires when you write to them. If your inner function only reads x and never modifies it, remove the nonlocal declaration entirely.
The cleaner architecture in most cases: pass x as a parameter to inner() and return the modified value. That removes the scope dependency entirely and makes the function testable in isolation.
def outer():
x = 10
def inner(val):
return val + 1
x = inner(x)
print(x) # Output: 11





