Desk Clarity

Everyday document & browser help

Python UnboundLocalError After Adding an Assignment: Return State Explicitly

By ON Lab · Sources checked November 9, 2026

Look for assignment anywhere in the function. It can make the name local, including before the assignment executes. Passing state in and returning the update makes ownership explicit.

Reproduce the boundary in a disposable example

A function can read an outer name until a local assignment changes its scope.

total = 10
def broken():
    total += 1
try:
    broken()
except UnboundLocalError:
    pass
else:
    raise AssertionError("expected local scope failure")
def increment(current):
    return current + 1
total = increment(total)
assert total == 11
print("explicit state update:", total)

Read the result before changing application code

The failing operation needs the old value as well as assigning a new one. Inspect conditional assignments and exception branches too. A branch that does not execute can still determine local scope. This example confirms the failure without changing an application’s global state.

Choose the behavior your caller needs

Use a parameter and return value for a calculation. Use nonlocal only when a nested function deliberately owns state in an enclosing function. Use global only for intentional module state, with all writers understood. Adding either declaration merely to suppress the exception can make later testing harder. Re-run both the branch that assigns and the branch that does not; each should have an explicit outcome.

Scope and limits

This is a name-binding diagnosis. It does not address concurrent updates, persistence or a missing attribute on an object.

Related: compare the adjacent data or execution boundary.

The embedded example was executed in an isolated local Python process on November 9, 2026. It is a reproducible boundary check, not a test of your full application.

Sources