fixhunt

biome complexity/noUselessUndefinedInitialization: fix changes program behavior

fix-changes-behaviorlabelled safereal · highduplicate
Findings / 2026-10-17T20-10-15-247Z-vb8k-biome-complexity_noUselessUndefinedInitialization / r1-p005biome 2.5.1511 → 8 lines2026-10-17 20:10 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

var hoisting and re-declaration inside loops or after use

Program

before
1function scopeTest() {
2 for (let i = 0; i < 2; i++) {
3 var a = undefined; // Rule triggers twice
4 console.log('Iteration', i, 'a =', a);
5 a = i * 10;
6 }
7}
8scopeTest();
after
1function scopeTest() {
2 for (let i = 0; i < 2; i++) {
3 var a ; // Rule triggers twice
4 console.log('Iteration', i, 'a =', a);
5 a = i * 10;
6 }
7}
8scopeTest();

Output

stdout beforeexit 0
Iteration 0 a = undefined
Iteration 1 a = undefined
stdout afterexit 0
Iteration 0 a = undefined
Iteration 1 a = 0
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory real · high

The fix removes the explicit `= undefined` initializer from a `var` declaration inside a loop. Because `var` is function-scoped, the original code re-initialized `a` to `undefined` on every iteration, while the fixed code only declares `a` once (hoisted) and retains its value from the previous iteration, changing the printed output.

Explanation Nemotron 3 Super unverified

The original code declares `var a` with an explicit initializer of `undefined`, which executes on each loop iteration due to hoisting but re-evaluates the assignment each time, resetting `a` to `undefined` before logging. The fix removes the initializer, leaving only the declaration `var a;`—which still hoists and initializes `a` to `undefined` once at function entry—but does not reassign it per iteration. Thus, on the second loop, `a` retains its prior value (`0` from `i * 10` when `i=0`) instead of being reset to `undefined`, changing the logged output. The behavior differs because the initializer’s per-iteration execution is lost.

Reproduce

file
prog.js (the before program)
minimized program
r1-p005.js
evidence sheet
r1-p005.md
regression fixture
r1-p005.js the minimized program with a header stating the observed change, for the tool's test suite
node prog.js
bunx @biomejs/biome lint --only=complexity/noUselessUndefinedInitialization --write prog.js
node prog.js

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

noUselessUndefinedInitialization fix · complexity noUselessUndefinedInitialization variable declaration · var initialization to undefined in loop body · removing redundant undefined assignment preserves value

  • duplicate biomejs/biome/issues/11938 Same rule removing `= undefined` from a `var` declaration inside a loop, causing the variable to retain its value across iterations instead of being reset each time.
  • related biomejs/biome/issues/6003 Same rule (noUselessUndefinedInitialization) but different context (Svelte file) and likely different cause.
  • related biomejs/biome/issues/6906 Same rule (noUselessUndefinedInitialization) but different construct (function with union return types).
  • related biomejs/biome/pull/8776 Same rule (noUselessUndefinedInitialization) fix for Svelte false positive, different construct.
  • related biomejs/biome/issues/2533 Original implementation issue for the same rule (noUselessUndefinedInitialization).

Details

program
Var Hoisting and Redeclaration in Loop
hazard
var hoisting and re-declaration inside loops or after use
oracle
stdout before: Iteration 0 a = undefined Iteration 1 a = undefined stdout after: Iteration 0 a = undefined Iteration 1 a = 0
run
2026-10-17T20-10-15-247Z-vb8k-biome-complexity_noUselessUndefinedInitialization
generated program (11 lines) and the fix's diff
1function scopeTest() {
2 console.log('a before loop:', typeof a); // hoisted, undefined
3 for (let i = 0; i < 2; i++) {
4 var a = undefined; // Rule triggers twice
5 console.log('Iteration', i, 'a =', a);
6 a = i * 10;
7 }
8 console.log('a after loop:', a); // Should be 10 from last iteration
9}
10
11scopeTest();
--- orig.js	2026-10-17 16:10:29.082376252 -0400
+++ fixed.js	2026-10-17 16:10:29.366367928 -0400
@@ -1,7 +1,7 @@
 function scopeTest() {
   console.log('a before loop:', typeof a); // hoisted, undefined
   for (let i = 0; i < 2; i++) {
-    var a = undefined; // Rule triggers twice
+    var a ; // Rule triggers twice
     console.log('Iteration', i, 'a =', a);
     a = i * 10;
   }
rule documentation given to the models
Summary

- Name: noUselessUndefinedInitialization
- Fix: safe
- Default severity: info
- Available from version: 1.7.2
- Diagnostic category: lint/complexity/noUselessUndefinedInitialization
- This rule is recommended

Description

 Disallow initializing variables to `undefined`.

 A variable that is declared and not initialized to any value automatically gets the value of `undefined`.
 It’s considered a best practice to avoid initializing variables to `undefined`.

 Please note that any inline comments attached to the initialization value or variable will be moved at the end of the variable declaration on auto-fix.
 Please be also aware that this differs from Eslint's behaviour.

Examples

Invalid

 ```js,expect_diagnostic
 var a = undefined;
 ```
 ```js,expect_diagnostic
 let b = undefined, c = 1, d = 2;
 ```
 ```js,expect_diagnostic
 for (let i = 0; i < 100; i++) {
 	let i = undefined;
 }
 ```
 ```js,expect_diagnostic
 let f = /**/undefined/**/ ;
 ```
Valid

 ```js
 var a = 1;
 ```
 ```js
 class Foo {
 	bar = undefined;
 }
 ```

 Exported variables are not flagged because in some frameworks (e.g., Svelte 4),
 initializing exported variables to `undefined` is used to declare optional props.

 ```js
 export let x = undefined;
 ```
 ```js
 let y = undefined;
 export { y };
 ```