{"record":{"id":"a647824ec654491c","repo":"oxc-project/oxc","slug":"too-many-nested-callbacks-num-maximum-allowed","errorCode":null,"errorMessage":"Too many nested callbacks ({num}). Maximum allowed is {max}.","messagePattern":"Too many nested callbacks \\((.+?)\\)\\. Maximum allowed is (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/eslint/max_nested_callbacks.rs","lineNumber":18,"sourceCode":"use oxc_ast::AstKind;\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_semantic::Semantic;\nuse oxc_span::{GetSpan, Span};\nuse schemars::JsonSchema;\nuse serde::Deserialize;\nuse serde_json::Value;\n\nuse crate::{\n    AstNode,\n    ast_util::{is_function_node, iter_outer_expressions},\n    context::LintContext,\n    rule::{DefaultRuleConfig, Rule},\n};\n\nfn max_nested_callbacks_diagnostic(num: u32, max: u32, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\"Too many nested callbacks ({num}). Maximum allowed is {max}.\"))\n        .with_help(\"Reduce nesting with promises or refactoring your code.\")\n        .with_label(span)\n}\n\n#[derive(Debug, Clone, JsonSchema, Deserialize)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\npub struct MaxNestedCallbacks {\n    /// The `max` enforces a maximum depth that callbacks can be nested.\n    max: u32,\n}\n\nconst DEFAULT_MAX_NESTED_CALLBACKS: u32 = 10;\n\nimpl Default for MaxNestedCallbacks {\n    fn default() -> Self {\n        Self { max: DEFAULT_MAX_NESTED_CALLBACKS }\n    }\n}","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/eslint/max_nested_callbacks.rs#L1-L36","documentation":"Emitted by the `max-nested-callbacks` rule when function callbacks are nested more deeply than allowed; oxc's default is `DEFAULT_MAX_NESTED_CALLBACKS = 10` (crates/oxc_linter/src/rules/eslint/max_nested_callbacks.rs:28). The visitor counts function expressions/arrow functions passed as arguments inside other callbacks, and the help text suggests promises or refactoring. It targets callback-hell maintainability.","triggerScenarios":"Chain 11 or more nested callbacks, typically with default max 10: nested waterfall Node.js style code, deeply chained libraries (`lib.a(x, (r1) => lib.b(r1, (r2) => ...))`), or repeated `array.map(() => array.map(() => ...))` layering beyond 10 levels. Config `{ \"max-nested-callbacks\": [\"error\", 3] }` makes it trigger much sooner.","commonSituations":"Legacy Node.js code from the pre-Promise era; code targeting very old browsers where promises/async-await were unavailable; enabling the rule with a strict max on an existing async codebase; recursively building config objects with nested callbacks.","solutions":["Refactor to async/await or promise chaining so nesting is flattened to sequential statements.","Name and hoist the inner callbacks (`function onUserLoaded(user) {...}`) so they become sibling declarations rather than nested expressions.","Raise `max` in config if the deep nesting is structural and unavoidable (e.g. generated glue code), or disable the rule for those files."],"exampleFix":"// before\ngetUser(id, (err, user) => {\n  getOrders(user, (err, orders) => {\n    getInvoices(orders, (err, invoices) => render(invoices));\n  });\n});\n\n// after\nconst user = await getUser(id);\nconst orders = await getOrders(user);\nconst invoices = await getInvoices(orders);\nrender(invoices);","handlingStrategy":"validation","validationCode":"// .oxlintrc.json -> \"max-nested-callbacks\": [\"error\", 3]\n// New async code review runs oxlint and fails anything deeper before merge.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write new async flow with async/await by default; callbacks only at API boundaries that require them.","Name and hoist callbacks instead of nesting them inline — named siblings are testable and reset the nesting count.","When maintaining pre-Promise code, wrap leaf callbacks once (`util.callbackify`) instead of adding another layer."],"tags":["eslint","oxlint","complexity","callbacks","async","callback-hell"],"backgroundTag":"nested-callbacks-lint","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}