Published · yesterdayBuild3 min read
A peer range dates the maintainer, not the code: jsx-a11y clears ESLint 10, react loses 38 rules
Same declared ESLint range, opposite outcomes: 39 jsx-a11y rules run clean on 10.9.0 while 38 of eslint-plugin-react's 101 throw, and one line of config moves 32 of them.
Written for builders.See today for builders
What happened
- [email protected] declares peerDependencies of eslint "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9".
- ESLint's current release is 10.9.0, so npm refuses to resolve [email protected] into the same tree, reporting a peer dependency resolution error.
- Installed with --legacy-peer-deps against ESLint 10 with all 39 rules the plugin exports enabled and pointed at ordinary JSX, eslint-plugin-jsx-a11y produced zero crashes.
- [email protected] declares an almost identical peer range, and under the same treatment 38 of its 101 rules threw.
- The reported error is: Error while loading rule 'react/display-name': contextOrFilename.getFilename is not a function.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
`resolveBasedir` is where both react numbers come from. It accepts either a string or a rule context, and when it gets the context it calls `contextOrFilename.getFilename()`, a method ESLint 10 removed [7]. Every rule that wants to know which React version you are running walks through that function, which is why the casualty list looks arbitrary next to what the rules actually check: `prop-types`, `no-multi-comp`, `sort-comp`, `hook-use-state` [8]. They are not version-sensitive checks. They just ask a question that no longer has an answer.
The arithmetic is worth doing by hand. The author of the eslint10-matrix survey reports 38 crashing rules with `settings: { react: { version: 'detect' } }` and 6 with no `settings.react.version` at all, same fixtures otherwise [9]. Thirty-eight minus thirty-two is six, and the six named survivors of the second run are precisely the ones failing on something other than version lookup: four on `isSpaceBetweenTokens`, one on `getSourceCode`, one on a `getFilename` call of its own [10][1]. So version detection accounts for the whole config-dependent surface, and one line in a shared config decides whether your CI reports 38 broken rules or 6 [9].
Then the harness, which is the part most people will get wrong. ESLint aborts the run at the first rule that throws, so "enable everything and count the failures" returns 1 no matter how bad the state is [11]. The fix used here is to lint with every rule on and, when that explodes, re-lint one rule at a time, 101 passes for a single plugin, affordable because `Linter.verify` on a handful of files takes milliseconds [12]. The first pass through that harness named `@typescript-eslint/eslint-plugin` the worst result in the set with 64 crashing rules [13]. It was wrong. Those rules were refusing to start because `parserOptions` was not configured to generate type information, and they failed identically on ESLint 9 [14]. The same control caught `typescript@latest` now being TS 7.0, which typescript-eslint hard-refuses, breaking four plugins in a shape that did not look like a version problem [16], and `--legacy-peer-deps` silently skipping peers, which left `@angular-eslint` without `@typescript-eslint/utils` and looking broken when it was fine [17].
The failure mode that no manifest can warn you about is vitest and eslint-plugin-deprecation, which never load at all: `Class extends value undefined is not a constructor or null` [18]. Neither plugin's own code is involved. `@typescript-eslint/utils` declares `class LegacyESLint extends eslint.LegacyESLint`, and ESLint 10 removed `LegacyESLint` when it removed eslintrc [19]. A declared ceiling of 9 can mean a clean run on 10 [1][3], and a plugin that declares nothing amiss can be dead two levels down its dependency tree [18]. The survey behind these numbers installs 54 plugins into clean temp directories against 9.39.5 and 10.9.0 nightly with every rule enabled [20], which is roughly the minimum shape of an answer that is not a guess about when someone last edited a JSON field.
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
[email protected] declares peerDependencies of eslint "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9".
ReportedView cited source - [2]
ESLint's current release is 10.9.0, so npm refuses to resolve [email protected] into the same tree, reporting a peer dependency resolution error.
ReportedView cited source - [3]
Installed with --legacy-peer-deps against ESLint 10 with all 39 rules the plugin exports enabled and pointed at ordinary JSX, eslint-plugin-jsx-a11y produced zero crashes.
ReportedView cited source - [4]
[email protected] declares an almost identical peer range, and under the same treatment 38 of its 101 rules threw.
ReportedView cited source - [5]
The reported error is: Error while loading rule 'react/display-name': contextOrFilename.getFilename is not a function.
ReportedView cited source - [6]
32 of the 38 crashing eslint-plugin-react rules fail with the contextOrFilename.getFilename error.
ReportedView cited source
Sources & coverage · 1 publisher
The reporting this story was synthesized from, earliest first. Every link goes to the original.
- dev.toChristoyesterdayeslint-plugin-jsx-a11y says it doesn't support ESLint 10. It does.
- dev.toVladimir Iglovikov13h agoMore Agent Autonomy Needs Stronger Guardrails: React 19 Linting on ESLint 10

