Quiz

What are the different types of errors in JavaScript?

Topics
JavaScript

TL;DR

Errors can be classified by when they appear—parse-time syntax errors, runtime exceptions, and logical errors that produce the wrong result. JavaScript also provides built-in exception classes such as SyntaxError, ReferenceError, TypeError, RangeError, URIError, and AggregateError. The class describes the failure category; application code can define domain-specific subclasses.

Handle only errors you can recover from or translate at that boundary. Preserve unexpected errors and their causes, and use tests and debugging tools for logical errors that do not throw.


Parse-time syntax errors

Invalid grammar prevents the script or module from being parsed:

// SyntaxError: Unterminated string constant
console.log('Hello);

Build tools and editors usually catch these before deployment. A try...catch inside the same malformed source cannot run because parsing never completed. Dynamically parsed code, such as JSON.parse() or eval(), can throw a SyntaxError that surrounding valid code catches.

Runtime exceptions

Syntactically valid code can throw while executing. Common built-in classes include:

  • ReferenceError: A binding does not exist or is accessed in its temporal dead zone.
  • TypeError: An operation is incompatible with the value, such as calling a non-function.
  • RangeError: A numeric value or recursion depth is outside an allowed range.
  • URIError: A malformed URI sequence is passed to a URI encoder or decoder.
  • AggregateError: Several failures are represented together, such as rejection from Promise.any().
  • EvalError: Retained for compatibility but rarely thrown by current engines.
try {
const user = null;
console.log(user.name);
} catch (error) {
console.log(error instanceof TypeError); // true
}

Do not branch on exact engine-generated message text; wording can differ by runtime. Use a known class, a stable application error code, or the API's documented result.

Logical errors

Logical errors run without throwing but violate the intended behavior:

const isAdmin = false;
if ((isAdmin = true)) {
console.log('Access granted'); // Incorrectly runs because this assigns true.
}

Static analysis can flag suspicious assignments, but authorization must ultimately be tested and enforced at a trusted boundary. Unit, integration, and property-based tests plus debugger output traces help find non-throwing defects.

Operational and programmer errors

Another useful application-level distinction is between expected operational failures and programming defects. A timeout, rejected card, or missing record may have a defined response. A violated invariant or calling a function with an impossible internal state usually should propagate to an error boundary and alert developers rather than being silently converted into success.

When wrapping an error to add context, use cause:

try {
await saveOrder(order);
} catch (cause) {
throw new OrderSubmissionError(order.id, { cause });
}

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise
Check your understanding Exercise

Which error classifications are correct? Select all that apply.