Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk4 min

Python UnboundLocalError: Check Where the Function Assigns Names

Python can raise UnboundLocalError even when a same-named global exists. Learn the function-scope rule, debug the failing path, and choose the right fix.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

UnboundLocalError means Python treated a name as local to a function, but the function tried to read it before that local name had been given a value. This can happen even when a global or enclosing variable with the same name already has a value: an assignment anywhere in the function normally makes the name local throughout that function.

Why does Python raise UnboundLocalError?

Python determines a function’s local names by examining its code block, not by checking which branch happens to run first. If a name is assigned anywhere in a function, Python treats references to that name in the function as references to its local binding—unless the function declares it global or nonlocal.

As an Amazon Associate I earn from qualifying purchases.

If execution reaches a read before that local binding has a value, Python raises UnboundLocalError. The language reference describes this as a local variable “that has not yet been bound to a value at the point where the name is used.” Python’s execution-model documentation explains the rule. UnboundLocalError is a subclass of NameError. The built-in exceptions reference documents the exception.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A global value can still be shadowed

In this example, the module-level x does not supply a value for the read inside foo:

x = 10

def foo():
    print(x)
    x += 1

foo()

The augmented assignment x += 1 binds x locally in foo. As a result, print(x) also refers to that local name, which has not yet been assigned a value. Python raises the error rather than falling back to the global x. A later ordinary assignment can create the same problem in a function that previously only read an outer variable. The Python Programming FAQ provides this example and explains the shadowing behavior.

Conditional assignments can leave a local uninitialized

A name assigned only in one branch is still local throughout the function. If another path reaches a read without running that assignment, the local has no value:

def label(is_ready):
    if is_ready:
        result = "ready"
    print(result)

Calling label(False) reaches the print without binding result. The issue is not that Python failed to find an outer value; the function’s own binding exists in the scope classification but has not been initialized on this path.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The same reasoning applies when assignments sit in loops, exception handlers, or other control-flow branches: inspect whether the path that fails actually executes a binding before the read.

How to debug the error

  1. Read the traceback. Find the function and exact variable named in the final exception line. Wording varies by Python version: Python 3.14.7 documentation shows cannot access local variable 'x' where it is not associated with a value, while older documentation shows local variable 'x' referenced before assignment. See the Python FAQ.
  2. Search the entire function for bindings. Look for ordinary assignments, augmented assignments such as +=, and assignments inside branches or handlers. A binding anywhere in the function can make the name local.
  3. Decide where the state belongs. Is it a value owned by this function, a module-level binding, or a binding in an enclosing function? The right fix depends on that intent.
  4. Check every relevant path. Follow branches, early returns, loops, and exception paths to see whether a local value is guaranteed before each read.
  5. Apply the matching fix and rerun the failing path. Also exercise paths that skip conditional assignments; the path that raised the error is the one that needs verification.

For interactive diagnosis, the Python FAQ identifies breakpoint(), pdb, and IDLE’s graphical debugger. It also names Visual Studio Code, Wing IDE, and PyCharm as IDEs with debuggers. For static checks, it lists Ruff, Pylint, and Pyflakes as basic bug-finding tools. These are options, not prerequisites; see the FAQ’s debugging guidance.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Which fix should you use?

Choose based on where the value should live and whether the function is supposed to rebind it. Initializing a local keeps the state within the function; scope declarations intentionally alter an outer binding. Passing a value in and returning a result often makes the data flow clearest.

Intended ownership Fix Effect
Local to this function Initialize it before any possible read Keeps ownership and updates inside the function.
Module-level binding Declare global name in the function Makes assignments rebind the module-level name.
Binding in an enclosing function Declare nonlocal name in the nested function Makes assignments rebind the existing name in the nearest enclosing function scope.
State that need not be rebound in an outer scope Pass it as a parameter, return a new value, or restructure around an explicit local Makes inputs and outputs explicit rather than changing outer-scope state.

Initialize a local when the function owns the value

Give the local a value before it can be read, on every path that reaches the read. For example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def label(is_ready):
    result = "not ready"
    if is_ready:
        result = "ready"
    print(result)

Before relying on a default, check that it is appropriate for all paths; initialization should represent the function’s intended behavior, not merely silence the exception.

Use global only for an intended module-level update

If the function is meant to rebind a module-level name, declare it before using that name in the function:

x = 10

def foo():
    global x
    print(x)
    x += 1

The declaration changes where assignments to x take effect. Use it when that shared module state is intentional, not as a generic repair for a missing local initialization.

Use nonlocal for an enclosing function’s binding

For a nested function that should update a name belonging to an enclosing function, use nonlocal:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def make_counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

Here count belongs to make_counter; increment intentionally rebinds that enclosing function’s name. The FAQ demonstrates both global and nonlocal as scope-specific solutions: Python Programming FAQ.

Prefer explicit data flow when outer rebinding is unnecessary

If a function only needs a value to calculate a result, accept it as a parameter and return the updated value instead of mutating a global or enclosing binding:

def increment(value):
    return value + 1

x = increment(x)

This makes the value’s source and destination visible at the call site and avoids changing outer-scope state from inside the function.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.