Skip to main content

JavaScript Errors

JavaScript Custom Errors

Written by Published

A custom error class describes a failure specific to your own program.

Extend the built-in Error class and give it a name.

Then the caller can tell your failures apart from everything else.

Example

Example

javascript

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

let name;
try {
  throw new ValidationError("name is required");
} catch (error) {
  name = error.name;
}

console.log(name);

The output is ValidationError.

Building One

Extend Error and call super(message).

Set this.name so the type shows up in logs.

Add any extra properties the handler will need.

Syntax

Syntax

javascript

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

super(message) must come first.

It Is Still an Error

A custom error passes every check a normal one does.

Example

Example

javascript

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

const error = new ValidationError("bad input");

console.log(error instanceof ValidationError);
console.log(error instanceof Error);
console.log(error.message);

All three confirm it behaves like a built-in error.

Carrying Extra Information

Add whatever the handler needs to react properly.

Example

Example

javascript

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

let details;
try {
  throw new ValidationError("is required", "email");
} catch (error) {
  details = error.field + " " + error.message;
}

console.log(details);

The output is email is required.

Handling Your Own Separately

instanceof distinguishes your errors from real bugs.

Example

Example

javascript

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

function handle(fn) {
  try {
    fn();
    return "worked";
  } catch (error) {
    return error instanceof ValidationError ? "show the user" : "log it as a bug";
  }
}

console.log(handle(function () { throw new ValidationError("bad"); }));
console.log(handle(function () { null.length; }));

A validation problem is the user's to fix; a TypeError is yours.

Forgetting the Name

Without setting name, it reports as Error.

instanceof still works, but logs are less useful.

Example

Example

javascript

class QuietError extends Error {}

const error = new QuietError("something");

console.log(error.name);
console.log(error instanceof QuietError);

Setting the name costs one line and helps every log message.

A Small Hierarchy

Custom errors can extend each other, just like any class.

Example

Example

javascript

class AppError extends Error {}
class NotFoundError extends AppError {}

const error = new NotFoundError("no such user");

console.log(error instanceof NotFoundError);
console.log(error instanceof AppError);
console.log(error instanceof Error);

A handler can catch the whole family with the base class.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Custom Errors</title>
</head>
<body>

  <h1>Custom Errors</h1>

  <p id="out"></p>

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

    function register(email) {
      if (!email) {
        throw new ValidationError("is required", "email");
      }
      return "registered";
    }

    const out = document.getElementById("out");

    try {
      out.textContent = register("");
    } catch (error) {
      if (error instanceof ValidationError) {
        out.textContent = "Problem with " + error.field + ": it " + error.message;
      } else {
        out.textContent = "Unexpected error";
      }
    }
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try a valid email:

Pass a real address and see it registered.

Important Points

  • Extend Error to make a custom error.
  • Call super(message) first.
  • Set this.name for clearer logs.
  • Extra properties carry the detail a handler needs.
  • instanceof separates your errors from genuine bugs.

Conclusion

Custom errors let a caller react to what actually went wrong.

The distinction between the user's mistake and yours is the useful one.

It costs a five-line class to get that clarity.