100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
JavaScript

Custom Errors in JavaScript

Building your own Error subclasses by extending the built-in Error class to represent domain-specific failures.

Error Handling & Interview PrepIntermediate11 min readJul 8, 2026
Analogies

1. Introduction

Built-in error types like TypeError and RangeError describe generic language-level failures, but real applications often have domain-specific failures — a failed validation, an insufficient balance, an expired session. Custom errors let you extend the built-in Error class to create named, structured error types that carry extra context and can be distinguished from one another with instanceof.

🏏

Cricket analogy: A generic 'no-ball' call is like TypeError — a broad rule violation — but a specific 'front-foot no-ball due to overstepping' call is like a custom error, giving umpires a named, structured reason they can distinguish from a 'height no-ball' using replay review, the way instanceof distinguishes custom error types.

2. Syntax

javascript
class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = "CustomError";
  }
}

throw new CustomError("Custom failure message");

3. Explanation

A custom error is defined with class X extends Error. Inside the constructor, super(message) MUST be called first — it invokes the Error constructor, which sets up this.message and the stack trace. After calling super, you should explicitly set this.name = "YourErrorName", because by default it inherits the generic name "Error" from the parent class, which makes err.name and stack traces less useful for identifying the specific failure.

🏏

Cricket analogy: Extending the Error class is like a specialist bowling academy extending the base fielding academy's curriculum — you must first complete the base academy's core certification (super(message)) before adding your specialty badge, and you must explicitly relabel your certificate 'Fast Bowling Specialist' instead of leaving it as the generic 'Academy Graduate' (this.name).

You can attach any extra properties you need (a field name, an HTTP status code, an original balance) directly on this inside the constructor, after calling super(). Consumers can then branch on the specific error type using instanceof, which correctly follows the prototype chain as long as the class properly extends Error.

🏏

Cricket analogy: Attaching extra properties like this.oversRemaining after calling super() is like a match report adding specific fields — overs left, required run rate — to a standard incident report; commentators can then branch their coverage using the report's specific type, just as code branches with instanceof.

Order matters: this is not usable in a derived class constructor until super() has been called, because super() is what actually creates the this binding for a subclass. Setting this.name before calling super(message) throws a ReferenceError.

4. Example

javascript
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

class InsufficientFundsError extends Error {
  constructor(balance, amount) {
    super(`Cannot withdraw ${amount}, balance is only ${balance}`);
    this.name = "InsufficientFundsError";
    this.balance = balance;
    this.amount = amount;
  }
}

function withdraw(balance, amount) {
  if (typeof amount !== "number" || amount <= 0) {
    throw new ValidationError("Amount must be a positive number", "amount");
  }
  if (amount > balance) {
    throw new InsufficientFundsError(balance, amount);
  }
  return balance - amount;
}

const attempts = [
  () => withdraw(100, 50),
  () => withdraw(100, 200),
  () => withdraw(100, -10),
];

for (const attempt of attempts) {
  try {
    console.log("New balance:", attempt());
  } catch (err) {
    if (err instanceof InsufficientFundsError) {
      console.log(`${err.name}: ${err.message}`);
    } else if (err instanceof ValidationError) {
      console.log(`${err.name} (${err.field}): ${err.message}`);
    } else {
      console.log("Unknown error:", err.message);
    }
  }
}

5. Output

text
New balance: 50
InsufficientFundsError: Cannot withdraw 200, balance is only 100
ValidationError (amount): Amount must be a positive number

6. Key Takeaways

  • Custom errors extend Error and must call super(message) before using this.
  • Always set this.name explicitly so err.name and stack traces identify the specific error type.
  • Extra domain data (field, status code, balance, etc.) can be attached as regular properties on this.
  • Use instanceof to branch handling logic based on the specific error subclass.
  • Order multiple instanceof checks from most specific to least specific when a hierarchy of custom errors exists.

Practice what you learned

Was this page helpful?

Topics covered

#JavaScript#JavaScriptProgrammingStudyNotes#Programming#CustomErrorsInJavaScript#Custom#Errors#Syntax#Explanation#StudyNotes#SkillVeris