Isolate State Bugs: Using PyCharm Conditional Breakpoints in Python
Use PyCharm conditional breakpoints to pause Python execution only when a specific state is reached, avoiding tedious manual stepping through irrelevant iterations.
24 Mar 2026, 16:32 UTC

The Problem: Debugging State Without Stopping Every Iteration
When a Python application misbehaves only under a specific state—such as a particular loop counter, a certain dictionary key, or an object attribute value—a standard breakpoint is too blunt. It halts on every execution of the line, forcing you to step through dozens or hundreds of irrelevant states. The useful takeaway is that PyCharm's conditional breakpoints let you attach a boolean expression to a breakpoint so the debugger suspends execution only when that expression evaluates to True in the current local scope.
Prerequisites
- A PyCharm project with Python code loaded in the editor.
- A run/debug configuration that uses the Python interpreter for your project.
- Basic familiarity with starting a debug session (Run → Debug or the bug icon).
- An understanding of the variables in scope at the target line.
Configuring a Conditional Breakpoint
Set a standard breakpoint first by clicking the gutter next to the target line. Then right-click the breakpoint marker to open its context menu. In older PyCharm versions the condition field may appear directly in the dialog; in current versions you typically see a Condition field where you enter a boolean Python expression. The expression is evaluated in the debugger's current frame each time the breakpoint is hit. If it returns True, execution pauses. If it returns False or raises an exception, execution continues.
For example, if you are iterating over a list of records and only want to stop when a record's status is "failed", you might enter record["status"] == "failed".
Validating the Expression First
Before you rely on a condition, run the debugger to any paused state near the target line and use the Evaluate Expression tool (Alt+F8). Paste your proposed condition into the dialog and evaluate it. If the result is True or False without an error, the syntax and names are valid for that scope. This prevents typos and missing-attribute errors from silently skipping the breakpoint during a long run.
Concrete Example: Pausing on a Specific Loop Iteration
Consider a data-processing loop that runs 100 times. A calculation error appears only near the middle of the dataset. Instead of pressing resume 99 times, attach a condition to the breakpoint inside the loop.
for i in range(100):
result = transform(i)
# Set breakpoint here with condition: i == 50
store(result)
With the condition i == 50, the debugger evaluates the expression on every iteration but suspends only when i equals 50. The Variables view should then show i as 50, confirming that the pause happened at the intended state.
Expected Checks
- Start the debug session and observe that execution does not pause on the first iteration.
- Confirm that the debugger pauses exactly once when the state matches the condition.
- Inspect the
Variablespane to verify that the values match the predicate you wrote. - Open the
Breakpointsdialog (Ctrl+Shift+F8) and confirm the condition is listed and enabled.
Recovery Options
If the conditional breakpoint never triggers, the expression may be raising an exception that PyCharm swallows, or the variable name may be out of scope. Open the Breakpoints dialog, disable the condition, and run again to verify the breakpoint itself is reachable. Once confirmed, re-enable the condition and use Evaluate Expression to test the logic at a nearby pause.
If the condition triggers too often, tighten the predicate by combining checks with and or by comparing a more specific attribute. If the debugger feels sluggish, simplify the expression or move the logic into a helper function that returns a boolean.
Limitations and Risks
Conditional breakpoints are not free. Every time the line is reached, PyCharm evaluates your expression in the debuggee process, which can add measurable overhead in tight loops or hot paths. Keep predicates simple and avoid calling expensive functions.
Never write a condition that mutates program state—such as counter += 1 or items.pop(). Side effects in a breakpoint condition can alter the behavior you are trying to observe, producing a Heisenbug: a defect that disappears or changes when you debug it. If you need to inspect a computed value without pausing, consider a log-to-console breakpoint instead, which prints a message and continues execution without suspending.
Finally, conditions that reference external modules require those modules to be importable in the active runtime environment. If the debugger cannot resolve a name, the breakpoint may be skipped silently.
Practical Verification
Create a minimal script with for i in range(100): pass. Set a breakpoint on the pass line and add the condition i == 50. Run the debugger. You should see exactly one suspension, and the Variables view should list i as 50. If you see more or fewer pauses, revisit the scope and syntax of your condition.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.