oxc-project/oxc · error
Unexpected return statement in constructor.
Error message
Unexpected return statement in constructor.
What it means
Diagnostic from the oxlint rule `no-constructor-return` (crates/oxc_linter/src/rules/eslint/no_constructor_return.rs). It fires on a `return` statement carrying a value inside a class MethodDefinition whose kind is `constructor`. Constructor return values are discarded when invoked with `new` (unless returning an object, which replaces `this` — a niche source of bugs), so returning a value signals confusion about constructor semantics.
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_constructor_return.rs:13
use oxc_ast::{
AstKind,
ast::{MethodDefinition, MethodDefinitionKind},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::Span;
use crate::{AstNode, context::LintContext, rule::Rule};
fn no_constructor_return_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected return statement in constructor.")
.with_help("Remove the return statement from the constructor. If you need early exit, use a bare `return;` with no value.")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct NoConstructorReturn;
declare_oxc_lint!(
/// ### What it does
///
/// Disallow returning a value from a constructor.
///
/// ### Why is this bad?
///
/// In JavaScript, returning a value in the constructor of a class may be a mistake.
/// Forbidding this pattern prevents mistakes resulting from unfamiliarity with the language or a copy-paste error.
///
/// ### ExamplesView on GitHub (pinned to e1e7af627c)
Solutions
- Remove the return statement so construction always yields `this`.
- For early exit, use a bare `return;` (no value) as the help text suggests, or throw on invalid input.
- If callers need a value or null on failure, convert to a factory function or static method (`Foo.create()` returning `new Foo()` or null).
- Never rely on returning a different object from a constructor unless that substitution is the documented design.
Example fix
// before
class Connection {
constructor(cfg) {
if (!cfg.url) return null;
}
}
// after
class Connection {
constructor(cfg) {
if (!cfg.url) throw new Error('url required');
}
} Defensive patterns
Strategy: validation
Validate before calling
// Gate: `return <value>;` inside a constructor (heuristic on class bodies)
const ctorReturn = /constructor\s*\([^)]*\)\s*\{[^}]*\breturn\s+[^;\s]/.test(src); Prevention
- Use bare `return;` for early exits; throw for invalid construction input.
- Move value-returning construction to factory/static create() methods.
- Remember constructor return values are discarded with new (unless replacing this).
When it happens
Trigger: A ReturnStatement with a non-null `argument` lexically inside a MethodDefinition with `kind == Constructor` — e.g. `class A { constructor() { return this.value; } }` or `constructor(x) { if (!x) return null; }`.
Common situations: Factory-ish classes converted from functions that returned values; early-exit validation written as `return null` in constructors; code moved between `function Foo()` and `class Foo` during modernization where the old return became meaningless or silently changes behavior when it returns an object.
Related errors
- Empty constructors are unnecessary
- Redundant super call in constructor
- Fixed size allocators are only supported on 64-bit little-en
- Expected to call `super()`.
- Lacked a call of `super()` in some code paths.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/53194304a9a15bcc.
Report an issue: GitHub.