Bird
Raised Fist0
Expressframework~10 mins

Custom error classes in Express - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Custom error classes
Define Custom Error Class
↓
Throw Custom Error in Route
↓
Express Error Middleware Catches Error
↓
Send Custom Error Response to Client
This flow shows how to create a custom error class, throw it in a route, catch it in Express error middleware, and send a response.
Execution Sample
Express
class NotFoundError extends Error {
  constructor(message) {
    super(message);
    this.name = 'NotFoundError';
    this.statusCode = 404;
  }
}

app.get('/item/:id', (req, res, next) => {
  if (!db.has(req.params.id)) {
    return next(new NotFoundError('Item not found'));
  }
  res.send(db.get(req.params.id));
});
Defines a custom error class and uses it in an Express route to handle missing items.
Execution Table
StepActionError InstanceMiddleware CalledResponse Sent
1Request to /item/123NoneNoNo
2Check if item exists in dbNoneNoNo
3Item not found, create NotFoundErrorNotFoundError('Item not found')NoNo
4Call next() with errorNotFoundError('Item not found')YesNo
5Error middleware receives NotFoundErrorNotFoundError('Item not found')YesNo
6Send response with status 404 and messageNotFoundError('Item not found')YesYes
7Request ends with 404 responseNoneNoYes
💡 Response sent with 404 status because item was not found.
Variable Tracker
VariableStartAfter Step 3After Step 4Final
errorundefinedNotFoundError('Item not found')NotFoundError('Item not found')undefined
Key Moments - 2 Insights
Why do we call next() with the error instead of sending a response directly?
Calling next(error) passes the error to Express error middleware, which centralizes error handling. See execution_table step 4 and 5.
What is the purpose of setting this.name and this.statusCode in the custom error?
this.name helps identify the error type, and this.statusCode lets middleware send the correct HTTP status. See execution_sample code.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, at which step does Express error middleware first handle the error?
AStep 3
BStep 5
CStep 4
DStep 6
💡 Hint
Check the 'Middleware Called' column in the execution_table.
According to variable_tracker, what is the value of 'error' after step 4?
ANotFoundError('Item not found')
Bundefined
Cnull
DError('Generic error')
💡 Hint
Look at the 'After Step 4' column for 'error' in variable_tracker.
If we did not set this.statusCode in the custom error, what would likely happen?
AThe error would not be caught by middleware
BExpress would send a 404 status anyway
CExpress would send a default 500 status
DThe server would crash
💡 Hint
Think about default HTTP status codes when no statusCode is set.
Concept Snapshot
Custom error classes extend Error to add properties like statusCode.
Throw them in routes with next(error) to trigger Express error middleware.
Middleware reads error properties to send proper HTTP responses.
This centralizes error handling and keeps routes clean.
Full Transcript
This visual execution trace shows how to create and use custom error classes in Express. First, a custom error class NotFoundError is defined extending the built-in Error class, adding a statusCode property. When a request comes in for an item, the route checks if the item exists. If not, it creates a NotFoundError instance and calls next() with it. Express then calls the error-handling middleware, which reads the error's statusCode and message to send a 404 response to the client. The variable tracker shows the error variable holding the NotFoundError instance during middleware handling. Key moments clarify why next(error) is used and why setting statusCode matters. The quiz tests understanding of middleware timing, variable state, and default error behavior.

Practice

(1/5)
1. What is the main purpose of creating a custom error class in an Express application?
easy
A. To define specific error types with custom messages and status codes
B. To replace the Express framework's built-in error handling completely
C. To avoid using try-catch blocks in asynchronous code
D. To automatically fix errors in the application code

Solution

  1. Step 1: Understand the role of custom error classes

    Custom error classes extend the built-in Error class to represent specific error types with meaningful messages and HTTP status codes.
  2. Step 2: Compare with other options

    Custom errors do not replace Express error handling but improve it; they do not fix code automatically or remove the need for try-catch.
  3. Final Answer:

    To define specific error types with custom messages and status codes -> Option A
  4. Quick Check:

    Custom error classes = specific error types [OK]
Hint: Custom errors add meaning and status codes to errors [OK]
Common Mistakes:
  • Thinking custom errors fix bugs automatically
  • Believing they replace Express error middleware
  • Assuming they remove try-catch necessity
2. Which of the following is the correct way to define a custom error class named NotFoundError that sets a 404 status code?
easy
A. function NotFoundError() { this.message = 'Not Found'; this.status = 404; }
B. class NotFoundError extends Error { constructor() { this.message = 'Not Found'; this.status = 404; } }
C. class NotFoundError { constructor() { this.message = 'Not Found'; this.status = 404; } }
D. class NotFoundError extends Error { constructor() { super('Not Found'); this.status = 404; } }

Solution

  1. Step 1: Check class inheritance and constructor

    The custom error class must extend Error and call super() with the message to set the error message properly.
  2. Step 2: Verify setting status property

    Setting this.status = 404 inside the constructor is correct for HTTP status code.
  3. Final Answer:

    class NotFoundError extends Error { constructor() { super('Not Found'); this.status = 404; } } -> Option D
  4. Quick Check:

    Extend Error + super() + status property = correct syntax [OK]
Hint: Always call super(message) when extending Error [OK]
Common Mistakes:
  • Not calling super() in constructor
  • Defining error as plain class without extending Error
  • Using function instead of class for custom error
3. Given the following code, what will be the output when throw new ValidationError('Invalid input'); is caught and logged?
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.status = 400;
  }
}

try {
  throw new ValidationError('Invalid input');
} catch (err) {
  console.log(err.message, err.status);
}
medium
A. Invalid input 400
B. Invalid input undefined
C. ValidationError 400
D. Error Invalid input

Solution

  1. Step 1: Understand the error message and status

    The ValidationError constructor calls super(message), so err.message is 'Invalid input'. The status property is set to 400.
  2. Step 2: Check console.log output

    Logging err.message and err.status prints 'Invalid input' and 400 separated by space.
  3. Final Answer:

    Invalid input 400 -> Option A
  4. Quick Check:

    err.message = 'Invalid input', err.status = 400 [OK]
Hint: super(message) sets err.message; status is custom property [OK]
Common Mistakes:
  • Expecting class name as message
  • Assuming status is undefined
  • Confusing Error default message with custom message
4. Identify the error in this custom error class definition:
class AuthError extends Error {
  constructor(message) {
    this.message = message;
    this.status = 401;
  }
}
medium
A. Constructor should not accept message parameter
B. Status code 401 is invalid for authentication errors
C. Missing call to super(message) in constructor
D. Class should not extend Error for custom errors

Solution

  1. Step 1: Check constructor of subclass of Error

    When extending Error, the constructor must call super(message) to properly initialize the error message.
  2. Step 2: Identify missing super call

    The code sets this.message directly but does not call super(), which causes errors in Error inheritance.
  3. Final Answer:

    Missing call to super(message) in constructor -> Option C
  4. Quick Check:

    Always call super(message) in Error subclass constructor [OK]
Hint: Always call super() first in Error subclass constructor [OK]
Common Mistakes:
  • Setting this.message without super()
  • Forgetting to extend Error
  • Using wrong status codes for errors
5. You want to create a custom error class DatabaseError that accepts a message and an optional error code, defaulting to 500. Which implementation correctly supports this and sets both status and code properties?
hard
A. class DatabaseError extends Error { constructor(message, code = 500) { super(message); this.status = code; this.code = 500; } }
B. class DatabaseError extends Error { constructor(message, code) { super(message); this.status = code || 500; this.code = code || 500; } }
C. class DatabaseError extends Error { constructor(message, code = 500) { super(message); this.status = 500; this.code = code; } }
D. class DatabaseError extends Error { constructor(message, code) { this.message = message; this.status = 500; this.code = code || 500; } }

Solution

  1. Step 1: Check constructor parameters and defaults

    class DatabaseError extends Error { constructor(message, code) { super(message); this.status = code || 500; this.code = code || 500; } } uses code parameter without default but uses code || 500 to set status and code, supporting optional code.
  2. Step 2: Verify super call and property assignments

    super(message) is called correctly; this.status and this.code are set to code or 500 if code is falsy.
  3. Step 3: Compare with other options

    class DatabaseError extends Error { constructor(message, code = 500) { super(message); this.status = 500; this.code = code; } } sets status always to 500 ignoring code parameter; class DatabaseError extends Error { constructor(message, code = 500) { super(message); this.status = code; this.code = 500; } } swaps status and code values; class DatabaseError extends Error { constructor(message, code) { this.message = message; this.status = 500; this.code = code || 500; } } misses super() call.
  4. Final Answer:

    class DatabaseError extends Error { constructor(message, code) { super(message); this.status = code || 500; this.code = code || 500; } } -> Option B
  5. Quick Check:

    Optional code with fallback and super() call = correct [OK]
Hint: Use code || 500 to set optional code with default [OK]
Common Mistakes:
  • Ignoring super() call
  • Swapping status and code values
  • Not supporting optional parameter correctly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard