oxc-project/oxc · error
'{name}' is a function.
Error message
'{name}' is a function. What it means
Diagnostic from oxlint's no-func-assign rule (ESLint port, eslint:recommended). It fires when an assignment target resolves to a symbol declared with a function declaration, overwriting the function binding. Reassigning function declarations is legal in sloppy mode but destroys the hoisted binding and confuses readers, so the rule reports "'{name}' is a function." with the label '{name} is re-assigned here'.
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_func_assign.rs:10
use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNode;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule};
fn no_func_assign_diagnostic(name: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("'{name}' is a function."))
.with_help("Do not re-assign a function declared as a FunctionDeclaration.")
.with_label(span.label(format!("{name} is re-assigned here")))
}
#[derive(Debug, Default, Clone)]
pub struct NoFuncAssign;
declare_oxc_lint!(
/// ### What it does
///
/// Disallow reassigning `function` declarations.
///
/// This rule can be disabled for TypeScript code, as the TypeScript compiler
/// enforces this check.
///
/// ### Why is this bad?
///
/// Overwriting/reassigning a function written as a FunctionDeclaration is often indicative ofView on GitHub (pinned to e1e7af627c)
Solutions
- Use a separate variable for the new value and keep the function binding intact.
- If the binding must change, declare with let (let calc = function () {...}) instead of a function declaration.
- Rename the function or the assignment target so they stop colliding.
- For deliberate test monkey-patching, suppress with // oxlint-disable-next-line eslint/no-func-assign.
Example fix
// before
function format(input) {
return input;
}
format = (input) => input.trim();
// after
function format(input) {
return input;
}
const formatTrimmed = (input) => input.trim(); Defensive patterns
Strategy: validation
Validate before calling
const fnNames = new Set([...source.matchAll(/^\s*function\s+(\w+)/gm)].map((m) => m[1])); const clobber = [...source.matchAll(/(\w+)\s*=[^=]/g)].some((m) => fnNames.has(m[1]));
Prevention
- Treat function declarations as immutable bindings.
- Inject or wrap mocks in tests instead of reassigning exported functions.
- Name replacement values distinctly instead of shadowing the function.
When it happens
Trigger: function calc() {} later followed by calc = otherFn;; compound writes like handler += wrap(handler) or handler ??= fallback; destructuring assignment [handler] = fns; where handler is a function declaration.
Common situations: Monkey-patching helpers in tests (render = mockRender); a refactor replaces a function's implementation by assigning over it instead of editing the declaration; two scripts defining the same global function name with one assigning over the other.
Related errors
- Do not assign to imported bindings
- Variable or `function` declarations are not allowed in neste
- Empty array binding pattern
- Empty object binding pattern
- Expected a conditional expression and instead saw an assignm
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/80e6cf5fbee6361a.
Report an issue: GitHub.