The undefined variable goes unnoticed
Environment data
- Pylance version: 2025.6.2
- OS and version: 6.6.87.2-microsoft-standard-WSL2 (Ubuntu)
- Python version (& distribution if applicable, e.g. Anaconda): Python 3.12.2
Code Snippet
counter += 1
ends up with correct:
"counter" is not defined [PyLance]
while
for i in range(100):
counter += 1
PyLance does not report anything
It seems that PyLance does not care about undefined variables in nested loops.
Expected behavior
The undefined variable in the nested loop is reported
Actual behavior
The undefined variable goes unnoticed.
Hi @hanpari, I'm an AI Support assistant here to help with your issue. While the team reviews your request, I wanted to provide some possible tips and documentation that might help you in the meantime.
Similar Issues (FYI only, not solutions)
The following issues may or may not be related to your report. They are provided for reference only, as they may describe similar symptoms, affect the same feature, or address related concerns, but may not be the same issue.
- Non-defined variable does not get reported when defined inside a loop: https://github.com/microsoft/pylance-release/issues/1888
The team will respond to your issue shortly. Please note this is a trial feature and may not be fully accurate. I hope these suggestions are helpful in the meantime. If this comment helped you, please give it a 👍. If the suggestion was not helpful or was incorrect, please give it a 👎. Your feedback helps us improve!
Transferring to Pyright as I'm not sure if this is expected behavior.
We will report a reportPossiblyUnboundVariable diagnostic if you set python.analysis.typeCheckingMode to standard or strict. Or alternatively you could specifically enable that diagnostic rule via:
"python.analysis.diagnosticSeverityOverrides": {
"reportPossiblyUnboundVariable": "warning"
}
The part I'm unclear about is that https://github.com/microsoft/pyright/issues/10648#issuecomment-3005141762 suggests that scenarios that would generate a NameError at runtime result in a reportUndefinedVariable diagnostic whereas scenarios that cause UnboundLocalError at runtime would result in a reportPossiblyUnboundVariable or reportUnboundVariable.
But in the scenario above and the scenarios in microsoft/pylance-release#1888, I get a NameError at runtime, so I'm wondering if they should be causing a reportUndefinedVariable diagnostic rather than reportPossiblyUnboundVariable.
The reportUndefinedVariable and reportUnboundVariable (and its variant reportPossiblyUnboundVariable) are related. In this case, I would expect the reportUndefinedVariable check to report an error. This was the case prior to pyright 1.1.394. This version introduced an apparent regression as part of this bug fix.
As a temporary workaround, you can enable the reportUnboundVariable and reportPossiblyUnboundVariable checks in pylance or set the typeCheckingMode to standard as @debonte mentions above.
The funny part is that the only way I got PyLance reported a warning for the code: "counter" is possibly unbound
for i in range(10):
counter += 1
I need to turn on both settings like this:
"python.analysis.diagnosticSeverityOverrides": {
"reportPossiblyUnboundVariable": "warning",
"reportUnboundVariable": "warning",
},
If any of them is commented out, I got no warning at all. This is pretty weird since the first line should be enough.
And I somewhat doubt that the variable is possibly unbound. There is no other variable in this context defined, so for me the UnboundVariable should be the correct warning. Perhaps I miss some use case where is possible to get a variable into the namespace that was taken into consideration.
As it turned out the setting python.analysis.typeCheckingMode is off by default. After turning it on, the issue disappears.
I would suggest turning it on by default.
Thanks, @debonte
I came across a bit similar problem:
# pyright: strict
def test() -> None:
def refine_elements() -> dict[int, str]:
for i in range(25):
refined_elements[i] = str(i)
# Expected: "refined_elements" is not defined
# Pyright: Type of "refined_elements" is "dict[int, str]"
reveal_type(refined_elements)
return refined_elements
refined_elements = refine_elements()
test()