fixhunt

biome complexity/noUselessUndefined: fix changes program behavior

fix-changes-behaviorlabelled safereal · highrelated
Findings / 2026-10-17T20-09-08-973Z-61rc-biome-complexity_noUselessUndefined / r1-p006biome 2.5.1520 → 10 lines2026-10-17 20:09 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

In strict mode, if `undefined` is reassigned globally, the literal `undefined` might not refer to the actual undefined value, but the rule only flags syntactic defaults, and the autofix removes the re

Program

before
1let log = [];
2(function(){
3 var undefined = 42; // shadowing
4 let x = undefined; // rule triggers: removes this line
5 log.push(String(x));
6})();
7try {
8} catch(e) {
9}
10console.log(log.join(' | '));
after
1let log = [];
2(function(){
3 var undefined = 42; // shadowing
4 let x ; // rule triggers: removes this line
5 log.push(String(x));
6})();
7try {
8} catch(e) {
9}
10console.log(log.join(' | '));

Output

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

Judge Nemotron 3 Ultra advisory real · high

The rule removes the initializer `undefined` from `let x = undefined`, turning it into `let x;`. In the program, a local variable named `undefined` shadows the global `undefined` with the value 42, so the original code assigns 42 to `x`. After the fix, `x` receives the true global `undefined`, changing the program's output from `42` to `undefined`. The documentation presents the rewrite as equivalent and does not mention shadowing, so this is an unsafe fix for a plausible construct.

Explanation Nemotron 3 Super unverified

The original code shadows the global `undefined` with a local variable initialized to 42 via `var undefined = 42`. The line `let x = undefined;` then assigns that local value (42) to `x`, so `String(x)` becomes `"42"`. After removal of the initializer, `let x;` declares `x` without initializing it, leaving it as the actual `undefined` value (since the local `undefined` variable is not a type but a variable name). Thus `String(x)` yields `"undefined"`, changing the output from `"42"` to `"undefined"`. The rewrite incorrectly assumes the identifier refers to the global `undefined` value, ignoring the lexical shadowing. This violates semantics because the initializer’s value depends on the scoped binding, not a predefined constant. Removing it alters the program’s state.

Reproduce

file
prog.js (the before program)
minimized program
r1-p006.js
evidence sheet
r1-p006.md
regression fixture
r1-p006.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/noUselessUndefined --write prog.js
node prog.js

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

noUselessUndefined fix · complexity noUselessUndefined variable declaration · shadowed global undefined assignment removal · unused undefined reference elimination

  • related biomejs/biome/issues/11934 same rule but different construct (parameter default vs variable declaration with shadowed undefined)
  • related biomejs/biome/issues/11017 same rule (noUselessUndefined) but different construct (TypeScript noImplicitReturns conflict)
  • related biomejs/biome/issues/6906 same rule (noUselessUndefined) but different construct (union return types in functions)

Details

program
Strict mode undefined shadowing made safe by removal
hazard
In strict mode, if `undefined` is reassigned globally, the literal `undefined` might not refer to the actual undefined value, but the rule only flags syntactic defaults, and the autofix removes the re
oracle
stdout before: 42 stdout after: undefined
run
2026-10-17T20-09-08-973Z-61rc-biome-complexity_noUselessUndefined
generated program (20 lines) and the fix's diff
1"use strict";
2let log = [];
3(function(){
4 var undefined = 42; // shadowing
5 let x = undefined; // rule triggers: removes this line
6 log.push(String(x));
7})();
8
9// After fix: x is undeclared -> ReferenceError
10try {
11 (function(){
12 var undefined = 42;
13 let x; // autofixed version
14 log.push(String(x));
15 })();
16} catch(e) {
17 log.push(e.name + ': ' + e.message);
18}
19
20console.log(log.join(' | '));
--- orig.js	2026-10-17 16:09:23.083459600 -0400
+++ fixed.js	2026-10-17 16:09:23.355450389 -0400
@@ -2,7 +2,7 @@
 let log = [];
 (function(){ 
   var undefined = 42; // shadowing
-  let x = undefined;  // rule triggers: removes this line
+  let x ;  // rule triggers: removes this line
   log.push(String(x));
 })();
 
rule documentation given to the models
Summary

- Name: noUselessUndefined
- Fix: safe
- Default severity: info
- Available from version: 2.0.0
- Diagnostic category: lint/complexity/noUselessUndefined


Description

 Disallow the use of useless `undefined`.

 `undefined` is the default value for new variables, parameters, return statements, etc., so specifying it doesn't make any difference.

 `return undefined` is allowed when the enclosing function has a return type annotation other than `undefined` or `void`.

Examples

Invalid

 ```js,expect_diagnostic
 let foo = undefined;
 ```

 ```js,expect_diagnostic
 const {foo = undefined} = bar;
 ```

 ```js,expect_diagnostic
 function foo() {
    return undefined;
 }
 ```

 ```js,expect_diagnostic
 function* foo() {
   yield undefined;
 }
 ```

 ```js,expect_diagnostic
 function foo(bar = undefined) {}
 ```

 ```js,expect_diagnostic
 function foo({bar = undefined}) {}
 ```

Valid

 ```js
 let foo;
 const {foo} = bar;
 function foo() {
   return;
 }
 function* foo() {
   yield;
 }
 function foo(bar) {}
 function foo({bar}) {}
 foo();
 ```

 ```ts
 function foo(): string | undefined {
   return undefined;
 }
 ```