We use cookies to enhance your experience on the site
CodeWorlds

Error Handling

In Jurassic Park, things go wrong - fences fail, sensors malfunction, dinosaurs escape. The safety protocols don't panic when problems arise - they follow structured procedures: detect the problem, categorize it, respond appropriately, and document what happened. JavaScript's error handling works exactly the same way.

try/catch/finally

The fundamental error handling structure:

1function checkFence(zoneId) {
2  try {
3    // Code that might throw an error
4    if (!zoneId) {
5      throw new Error('Zone ID is required');
6    }
7
8    const status = getFenceStatus(zoneId); // may throw
9    console.log(`Fence OK: ${status}`);
10    return status;
11
12  } catch (error) {
13    // Handle the error
14    console.error(`Fence check failed: ${error.message}`);
15    return 'UNKNOWN';
16
17  } finally {
18    // Always executes - cleanup code
19    console.log('Fence check procedure complete');
20  }
21}

Built-in Error Types

JavaScript has several built-in error types:

1// TypeError - wrong type
2try {
3  null.property; // cannot read property of null
4} catch (e) {
5  console.log(e instanceof TypeError); // true
6  console.log(e.message); // "Cannot read properties of null"
7}
8
9// RangeError - value out of valid range
10try {
11  new Array(-1); // invalid array length
12} catch (e) {
13  console.log(e instanceof RangeError); // true
14}
15
16// ReferenceError - using undefined variable
17try {
18  console.log(undeclaredVar);
19} catch (e) {
20  console.log(e instanceof ReferenceError); // true
21}
22
23// SyntaxError - rare at runtime (usually compile-time)
24try {
25  eval('function('); // invalid syntax
26} catch (e) {
27  console.log(e instanceof SyntaxError); // true
28}

throw - Throwing Errors

You can throw any value, but it's best practice to throw

Error
objects:

1function validateDinoData(data) {
2  if (!data.name) {
3    throw new TypeError('Dinosaur name is required');
4  }
5
6  if (data.weight <= 0) {
7    throw new RangeError(`Weight must be positive, got ${data.weight}`);
8  }
9
10  if (!['carnivore', 'herbivore', 'omnivore'].includes(data.diet)) {
11    throw new Error(`Unknown diet type: ${data.diet}`);
12  }
13
14  return true;
15}
16
17try {
18  validateDinoData({ name: 'Rex', weight: -100, diet: 'carnivore' });
19} catch (e) {
20  if (e instanceof RangeError) {
21    console.log('Invalid range:', e.message);
22  } else if (e instanceof TypeError) {
23    console.log('Type error:', e.message);
24  } else {
25    console.log('Unknown error:', e.message);
26  }
27}

Custom Error Classes

Create your own error types for domain-specific errors:

1class ParkError extends Error {
2  constructor(message, code) {
3    super(message);
4    this.name = 'ParkError';
5    this.code = code;
6  }
7}
8
9class FenceBreachError extends ParkError {
10  constructor(zone, dinoName) {
11    super(`Fence breach in zone ${zone} - ${dinoName} escaped!`, 'FENCE_BREACH');
12    this.name = 'FenceBreachError';
13    this.zone = zone;
14    this.dinoName = dinoName;
15  }
16}
17
18class DinoHealthCriticalError extends ParkError {
19  constructor(dinoName, health) {
20    super(`${dinoName} health critical: ${health}%`, 'HEALTH_CRITICAL');
21    this.name = 'DinoHealthCriticalError';
22    this.dinoName = dinoName;
23    this.health = health;
24  }
25}
26
27try {
28  throw new FenceBreachError('A', 'Rex');
29} catch (e) {
30  if (e instanceof FenceBreachError) {
31    console.log(`BREACH! Zone: ${e.zone}, Dinosaur: ${e.dinoName}`);
32    console.log(`Code: ${e.code}`);
33  } else if (e instanceof ParkError) {
34    console.log(`Park error: ${e.message}`);
35  } else {
36    throw e; // re-throw unknown errors!
37  }
38}

Optional Chaining (?.)

?.
safely accesses nested properties - returns
undefined
instead of throwing:

1const park = {
2  zones: {
3    A: {
4      dinos: [{ name: 'Rex', health: 95 }]
5    }
6  }
7};
8
9// Without optional chaining - might throw
10// const health = park.zones.B.dinos[0].health; // TypeError!
11
12// With optional chaining - safe
13const healthA = park.zones?.A?.dinos?.[0]?.health;
14console.log(healthA); // 95
15
16const healthB = park.zones?.B?.dinos?.[0]?.health;
17console.log(healthB); // undefined - no error!
18
19// With method calls
20const status = park.zones?.A?.getStatus?.();
21console.log(status); // undefined (method doesn't exist - no error)

Nullish Coalescing (??)

??
returns the right side only when the left is
null
or
undefined
(not
0
,
false
, or `''``):

1const dinoHealth = null;
2const defaultHealth = 100;
3
4// ?? vs ||
5console.log(dinoHealth ?? defaultHealth);  // 100 (null → use default)
6console.log(0 ?? defaultHealth);           // 0 (0 is not null/undefined!)
7console.log(0 || defaultHealth);           // 100 (0 is falsy with ||)
8
9const config = {
10  voltage: 0,      // explicitly 0
11  active: false,   // explicitly false
12  name: ''         // empty string
13};
14
15// ?? respects explicit false-y values
16console.log(config.voltage ?? 10000);  // 0 (explicit 0 respected)
17console.log(config.active ?? true);    // false (explicit false respected)
18console.log(config.name ?? 'unnamed'); // '' (explicit empty string respected)
19console.log(config.missing ?? 'N/A'); // 'N/A' (undefined → use default)

Combined Pattern

1function getDinoHealth(park, zoneName, dinoIndex) {
2  try {
3    const health = park?.zones?.[zoneName]?.dinos?.[dinoIndex]?.health ?? 'unknown';
4    return health;
5  } catch (e) {
6    console.error(`Error getting health: ${e.message}`);
7    return 'error';
8  }
9}
10
11// Works safely even with missing data
12console.log(getDinoHealth(park, 'A', 0)); // 95
13console.log(getDinoHealth(park, 'B', 0)); // "unknown"
14console.log(getDinoHealth(null, 'A', 0)); // "unknown"

"Error handling is like the park's emergency response protocol" - says Dr. Rex. "You don't panic when an alarm sounds - you check the type of alarm, follow the procedure, document everything. try/catch is that structured response, and custom errors are the specific alarm types!"

Go to CodeWorlds