Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 12

Error Handling

Prerequisites: this chapter assumes you know functions, control flow, and promises/async-await as covered earlier in the spine.
Level: AdvancedLength: Mid1 min read

Read at another depth

Error Handling

Prerequisites: this chapter assumes you know functions, control flow, and promises/async-await as covered earlier in the spine.

The model

JavaScript errors are thrown values. throw accepts any value, but only Error instances (or subclasses) produce a stack trace, so always throw Error subclasses. try/catch/finally is the only recovery mechanism; there is no checked exceptions concept, so type signatures and documentation carry the burden of signaling failure.

The catch-all trap

catch (e) catches everything, including programming mistakes like TypeError: cannot read property of undefined. Advanced practice narrows the catch:

Code example in javascript
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}

async function saveUser(input) {
  try {
    validate(input);
    return await api.post('/users', input);
  } catch (err) {
    if (err instanceof ValidationError) {
      return { ok: false, reason: 'validation', field: err.field };
    }
    throw err; // rethrow unknown failures
  }
}

Notice the rethrow. Swallowing unknown errors converts a loud bug into silent corruption.

Failure modes

  • finally interactions: finally runs even during return or throw from the try block. A return inside finally silently discards any pending throw — never do it.
  • Async errors escape try blocks: a throw inside a promise you forgot to await will not hit your catch. This is the most common async failure mode:
Code example in javascript
try {
  doAsyncWork().then(report); // rejection escapes this catch
} catch (err) { /* never runs for a rejection */ }

try {
  await doAsyncWork(); // awaited — the catch sees the rejection
} catch (err) { /* runs */ }
  • Floating promises: any call returning a promise without await or .catch() is an unhandled rejection risk. Top-level, use await or attach a handler.
  • Lossy rethrows: wrapping an error in a new one without a cause destroys the original stack. Use the cause option:
Code example in javascript
try {
  parseConfig(raw);
} catch (err) {
  throw new Error('config invalid', { cause: err });
}

finally as cancellation

finally is for symmetric cleanup, not control flow:

Code example in javascript
const handle = openResource();
try {
  process(handle);
} finally {
  handle.close(); // runs on success, throw, or early return
}

Decision criteria

SituationApproach
Expected, recoverable (validation, 404)Catch, inspect type, return a result
Programming bug (undefined access)Let it crash; don't catch broadly
Retryable I/OCatch, wrap with `cause`, retry with backoff
Top-level boundary (server request, event handler)Catch-all, log with full stack, respond safely

Rule of thumb: catch only what you can meaningfully handle at that layer; otherwise enrich and rethrow.

diagram mermaid caption: Error propagation from a nested async call to a top-level boundary. alt: Flow diagram showing a throw inside doAsyncWork propagating through saveUser's try/catch, being rethrown, and finally caught by the top-level handler.

exercise Q: Why doesn't catch around a non-awaited promise call observe its rejection? A: The promise's rejection is asynchronous and happens after the try block finishes; without await (or .catch), no code in that try is linked to the promise's eventual failure, so the rejection escapes as an unhandled rejection.

Spotted a mistake, or code that does not work?

Report an issue

Chapter: Error Handling

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that