Skip to content

eslint-factory: require-async-entrypoint-catch only tracks FunctionDeclaration, missing async fn-expression/arrow entrypoints an [Content truncated due to length] #43129

Description

@github-actions

Summary

require-async-entrypoint-catch (the newest rule) only detects module-scope async FunctionDeclarations and only flags a bare Identifier() ExpressionStatement. Two common entrypoint shapes silently escape the rule, producing false negatives for exactly the unhandled-rejection class the rule exists to catch.

Gap 1 — async function expressions / arrow functions assigned at module scope

The collector only handles FunctionDeclaration:

FunctionDeclaration(node) {
  if (node.async && node.id?.name && node.parent.type === AST_NODE_TYPES.Program) {
    asyncFunctionNames.add(node.id.name);
  }
},

So these equivalent entrypoints are never tracked and their bare calls are never flagged:

const main = async () => { /* ... */ };
main();                       // FN: unhandled rejection, not flagged

const run = async function () { /* ... */ };
if (require.main === module) run();   // FN

The rule's own test suite documents this boundary (only FunctionDeclaration cases are covered; const main = async () => {} appears only in a valid/await case).

Gap 2 — .then() chained without a .catch()

The call handler bails whenever the callee is not a plain Identifier, so a .then() chain with no rejection handler is treated as "handled":

main().then(() => process.exit(0));   // FN: rejection still unhandled

(A chain that does end in .catch(...) should remain valid, as it is today.)

Grounding / severity

Current live actions/setup/js entrypoints are all either sync function main() (correctly ignored) or async FunctionDeclarations that the rule already catches (e.g. parse_mcp_scripts_logs.cjs:415, parse_token_usage.cjs:238 — true positives). Arrow/expression async entrypoints presently appear only as await-guarded helpers, so this is a preventive robustness/parity refinement: the sibling error-property rules were hardened for computed/aliased forms for the same reason, and detection here should not depend on the author's choice of declaration syntax.

Acceptance criteria

  • Track module-scope async entrypoints declared as const/let/var X = async function () {} and const/let/var X = async () => {} (VariableDeclarator with an async init), in addition to FunctionDeclaration.
  • Flag a bare X() ExpressionStatement for such tracked names, with the existing .catch(...) suggestion fix.
  • Flag X().then(...) ExpressionStatements that do not terminate in a .catch(...); keep chains ending in .catch(...) valid.
  • Add RuleTester cases: valid (.catch present, awaited inside async, sync arrow) and invalid (bare arrow/fn-expr call, .then() without catch) with expected suggestion output.
  • No new false positives against the existing actions/setup/js/**/*.cjs corpus.

See also #42189 / #42915 (branch-order guard FNs in the sibling catch-error-property rules) — same theme of tightening the newest error-handling rules against real-world variance.

Generated by 🤖 ESLint Refiner · 147.1 AIC · ⌖ 12.9 AIC · ⊞ 4.7K ·

  • expires on Jul 9, 2026, 10:27 PM UTC-08:00

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions