Error Types & Exception Names

12 common programming errors explained in plain English — what they mean, when you see them, what causes them, and how to think about fixing them.

SyntaxError

Compile-time

The code is not written according to the language rules — the parser cannot understand it at all.

Detected by the interpreter/compiler before the code runs. The program never starts.

// Python
print("Hello"
       ↑ SyntaxError: unexpected EOF — missing closing parenthesis

// JavaScript
const x = {name: "Alice" age: 30}
                       ↑ SyntaxError: missing comma
  • Missing parenthesis, bracket, or semicolon
  • Misspelled keyword (`funtion` instead of `function`)
  • Mismatched quotes or brackets
  • Invalid indentation in Python
SyntaxError is the easiest category to fix — your IDE highlights it immediately. It is also the one most beginners encounter first.

TypeError

Runtime

An operation is performed on a value of the wrong type — like calling a number as if it were a function.

At runtime, when the code tries to do something a value does not support.

// JavaScript
const num = 42;
num();  // TypeError: num is not a function

const user = null;
console.log(user.name);
  // TypeError: Cannot read properties of null
  • Calling a non-function as a function
  • Accessing properties on `null` or `undefined`
  • Expecting a string but receiving an array
  • Wrong argument type passed to a function
Extremely common in JavaScript due to dynamic typing. TypeScript was created largely to catch TypeErrors before runtime.

ReferenceError

Runtime

The code refers to a variable or function that does not exist (has not been declared).

At runtime, when the JavaScript engine looks up a name and cannot find it in scope.

// JavaScript
console.log(userName);
  // ReferenceError: userName is not defined

function greet() {
  const msg = "Hello";
}
console.log(msg);
  // ReferenceError: msg is not defined (out of scope)
  • Using a variable before declaring it (`let`/`const` in the temporal dead zone)
  • Typo in a variable name
  • Accessing a variable outside its scope
  • Forgetting to import a module
Very common cause: writing `funciton` or `calback` (typo) — the correct name is not found.

NullPointerException

Runtime

The code tries to use an object reference that points to nothing (null). Mostly a Java / Kotlin / C# concept.

At runtime, when a method is called or a field is accessed on a null reference.

// Java
String name = null;
System.out.println(name.length());
  // NullPointerException: Cannot invoke "String.length()" because "name" is null

// The equivalent in JavaScript is a TypeError:
const user = null;
user.getName();  // TypeError: Cannot read properties of null
  • A method returns null in an edge case you didn't handle
  • Optional value not checked before use
  • Object not initialised before use
  • Database query returned no result and the null was not handled
Tony Hoare, who invented null in 1965, called it his "billion-dollar mistake". Modern languages (Kotlin, Swift, Rust) have null-safety built in to prevent this class of error.

IndexOutOfBoundsException

Runtime

The code tries to access an element in an array (or list) at an index that does not exist.

At runtime, when accessing `array[i]` where `i` is negative or ≥ the array length.

// Java
List<String> items = List.of("a", "b", "c");
items.get(5);
  // IndexOutOfBoundsException: Index 5 out of bounds for length 3

// Python equivalent
items = ["a", "b", "c"]
items[5]
  // IndexError: list index out of range
  • Off-by-one error (`i <= length` instead of `i < length`)
  • Accessing `items[items.size()]` instead of `items[items.size() - 1]`
  • Loop boundary not matching the collection size
  • Empty array not handled before access
The "off-by-one" bug is so universal that programmers joke: "There are two hard things in CS: naming things, cache invalidation, and off-by-one errors."

StackOverflowError

Runtime

The call stack ran out of space — usually caused by infinite recursion (a function that keeps calling itself forever).

At runtime, when the maximum call stack depth is exceeded.

// JavaScript
function countDown(n) {
  return countDown(n - 1);  // no base case!
}
countDown(100000);
  // RangeError: Maximum call stack size exceeded

// Java equivalent in recursive code
// java.lang.StackOverflowError
  • Recursive function with no base case (or an incorrect one)
  • Mutual recursion: A calls B, B calls A, infinitely
  • Extremely deep (but valid) recursion exceeding language limits
StackOverflow.com took its name from this error — it's one of the most universally recognised bugs. The fix is almost always: add a base case to your recursion, or refactor to iteration.

OutOfMemoryError

Runtime

The application tried to allocate more memory (heap space) than the system has available.

At runtime, when allocation fails — typically during intensive data processing or due to a memory leak.

// Java
// java.lang.OutOfMemoryError: Java heap space
List<byte[]> list = new ArrayList<>();
while (true) {
    list.add(new byte[1024 * 1024]);  // allocate 1MB forever
}

// Node.js
// FATAL ERROR: Reached heap limit — Allocation failed
  • Memory leak: objects accumulate and are never garbage-collected
  • Loading an enormous file or dataset into memory all at once
  • Creating too many objects in a tight loop without releasing them
  • Cache with no eviction policy growing unboundedly
In Java, you can increase heap size with `-Xmx` JVM flag. In Node.js with `--max-old-space-size`. But the real fix is to find and fix the memory leak.

RuntimeError

Runtime

A general catch-all error category raised when something goes wrong during execution that doesn't fit a more specific type.

At runtime. Mostly a Python term — other languages raise more specific exception types.

# Python
import sys
if sys.getrecursionlimit() == 0:
    raise RuntimeError("recursion limit is 0")

# Also raised when a generator is already closed:
def gen():
    yield 1
g = gen()
next(g)
g.close()
next(g)  # RuntimeError: generator already executing
  • Logic condition detected as invalid state
  • Using a resource after it has been closed
  • Version mismatch between packages
  • Reaching code that should be unreachable
When you see RuntimeError in Python, the message content is the key — the error name itself is not very specific.

TimeoutError

Network / I/O

A requested operation did not complete within the allowed time — the waiting period expired.

During network calls, database queries, or any timed operation that takes too long.

// fetch with AbortController timeout
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);

fetch('/api/data', { signal: controller.signal })
  .catch(err => {
    if (err.name === 'AbortError') {
      console.error('Request timed out after 5s');
    }
  });

// Python requests
requests.get('https://example.com', timeout=5)
  # requests.exceptions.Timeout
  • Slow database query with no index on a large table
  • Downstream service is overloaded or unreachable
  • Network latency spike (especially cross-region)
  • Deadlock in the database waiting for a lock to release
Always set timeouts on network calls and DB queries — without them, your threads can block forever during an outage, eventually exhausting the thread pool.

ConnectionRefused

Network / I/O

The attempt to connect to a server was explicitly rejected — no service is listening on the target port.

When your application tries to open a TCP connection to a host:port where nothing is running or accepting connections.

# Python
import socket
s = socket.create_connection(('localhost', 5432))
  # ConnectionRefusedError: [Errno 111] Connection refused

# Common Docker scenario:
# Your app container starts before the DB container is ready
# ERROR: connect ECONNREFUSED 127.0.0.1:5432
  • The target service has not started yet (common in Docker Compose startup ordering)
  • Typo in the host or port in your config
  • Firewall blocking the port
  • The service crashed and is not running
Different from a Timeout: ConnectionRefused is immediate — the OS actively rejects the connection. A Timeout means no response at all (host may be unreachable or packet dropped).

PermissionDenied

System

The process does not have the system-level permission to access a file, directory, or resource.

When trying to read, write, or execute a file/resource that the operating system has restricted.

# Linux / macOS
open('/etc/shadow', 'r')
  # PermissionError: [Errno 13] Permission denied: '/etc/shadow'

# Writing to a read-only file
open('/usr/local/bin/app', 'w')
  # [Errno 13] Permission denied

# Common in Docker: running as root vs. non-root user
# EACCES: permission denied '/app/data/output.json'
  • File owned by root, but app runs as an unprivileged user
  • Incorrect file permissions (`chmod 600` instead of `chmod 644`)
  • Running in a container without the right user/volume permissions
  • Missing IAM role or policy (cloud storage, AWS S3 etc.)
In cloud and container contexts, this error is extremely common. The principle of least privilege intentionally prevents processes from accessing things they shouldn't — tune the permissions rather than running everything as root.

LogicError

Logic

The code runs without crashing, but produces the wrong result — the algorithm itself is incorrect.

At runtime — no exception is thrown. Only caught by tests, incorrect output, or user reports.

// Calculating average — wrong result, no crash
function average(numbers) {
  let sum = 0;
  for (let i = 0; i <= numbers.length; i++) {  // bug: <= instead of <
    sum += numbers[i];
  }
  return sum / numbers.length;
}
// NaN returned because numbers[numbers.length] is undefined
  • Off-by-one error in a loop boundary
  • Wrong formula (e.g., dividing before multiplying, wrong operator)
  • Incorrect conditional (`>=` instead of `>`, `&&` instead of `||`)
  • Mutating shared state unexpectedly
Logic errors are the hardest to find — no crash, no red squiggles in the IDE. Only thorough tests catch them. This is why test-driven development advocates writing tests before code.

Quick Reference

Error name Category Plain meaning Language
SyntaxErrorCompile-timeCode grammar is wrong — cannot be parsedJS, Python, most
TypeErrorRuntimeWrong type used in an operationJS, Python
ReferenceErrorRuntimeVariable or name not found in scopeJS
NullPointerExceptionRuntimeUsed a reference that points to nullJava, Kotlin, C#
IndexOutOfBoundsExceptionRuntimeArray/list index does not existJava; IndexError in Python
StackOverflowErrorRuntimeCall stack exhausted (infinite recursion)Java; RangeError in JS
OutOfMemoryErrorRuntimeNo heap memory left to allocateJava; fatal in Node.js
RuntimeErrorRuntimeGeneral execution error (no crash name)Python
TimeoutErrorNetwork / I/OOperation took too longAll (varies by library)
ConnectionRefusedNetwork / I/ONothing is listening on that portOS-level, all languages
PermissionDeniedSystemOS rejected the file/resource accessOS-level, all languages
Logic ErrorLogicWrong output, no exception thrownAll (caught by tests only)