-
Notifications
You must be signed in to change notification settings - Fork 20
Description
System Info
System: macOS 26.2, CPU (10) ar64 Apple M4, and Shell 5.9 /bin/zsh
Binaries: Node.js 24.1.0, npm 11.6.2, pnpm 10.28.0, Watchman 2025:08:11:00
Browsers: Installed web browsers. Chrome 144.0.7559.110. Safari: 26.2
npmPackages: React 19.2.4, typescript 5.9.3 -> 5.9.3
Details
I tried this code:
class PanelErrorBoundary extends Component<PanelErrorBoundaryProps, PanelErrorBoundaryState> {
// ... constructor and other methods ...
render() {
if (this.state.hasError) {
return <PanelError panelId={this.props.panelId} error={this.state.error} onRetry={this.handleReset} />;
}
return this.props.children;
}
}
// And also this arrow function:
const renderPanelContent = () => {
switch (props.panelId) {
case PANEL_IDS.CHAT:
return children;
// ...
}
};
I expected this to happen: The code should remain unchanged, or at most receive formatting fixes. The @typescript-eslint/require-await rule is explicitly disabled in our config:
{
"rules": {
"@typescript-eslint/require-await": "off"
}
}
Instead this happened: The auto-fixer inserted multiple async keywords, creating invalid syntax:
- render() {
+ async async async render() {
- const renderPanelContent = () => {
+ const renderPanelContent = async async async () => {
This breaks React completely because:
React class component render() must be synchronous to return JSX immediately
Making it async returns a Promise, which React cannot handle
The triple async is invalid JavaScript syntax
Meta
rslint -V: 0.2.0
Additional context
The behavior suggests the fixer is malfunctioning in two ways:
It runs despite @typescript-eslint/require-await being explicitly disabled
It appears to be operating in reverse logic - instead of removing unnecessary async markers, it's adding them recursively in a single pass
This creates a loop where the linter introduces syntax errors rather than resolving them.
Workaround: We've added a warning comment to affected files and have to manually revert the changes after CI runs:
/**
⚠️ LINTER BUG WARNING: The auto-fix workflow (pnpm lint:fix) has a bug that- inserts "async async async" before render() and renderPanelContent().
- If you see "async async async render()" after CI runs, remove the async keywords.
- React class component render() must be synchronous.
*/
Reproduce link
No response
Reproduce Steps
markdown
Minimal Reproduction
Here are the simplest steps to reproduce the recursive async auto-fix bug:
1. Create a Reproduction File (repro.tsx)
Create a file with the following class component and arrow function pattern. Note that the render() method is synchronous.
import React, { Component } from 'react';
class PanelErrorBoundary extends Component {
state = { hasError: false, error: null };
// The fixer targets this synchronous render method
render() {
if (this.state.hasError) {
return <div>Error</div>;
}
return this.props.children;
}
}
// It also targets this arrow function
const renderPanelContent = () => {
switch (props.panelId) {
case 'CHAT':
return children;
}
};2. Configuration
Ensure the rule is explicitly disabled in your config:
{
"rules": {
"@typescript-eslint/require-await": "off"
}
}3. Execute Linter
Run the fix command:
pnpm lint:fixActual Result: The linter inserts async async async recursively before render() and the arrow function, causing syntax errors.