Skip to lesson
Python for JS Developers

Modules & ErrorsLesson 3 of 3

Error Handling

4 min

The structure is almost identical: try/catch becomes try/except, throw becomes raise, and Error subclasses become Exception subclasses. You will adjust in minutes.

The real difference is Python's else clause on try blocks. The else block runs ONLY if no exception was raised, which is perfect for code that should execute after the risky operation succeeds but should not be inside the try block itself (so its own errors are not accidentally caught). JS has no equivalent.

Context managers (with statements) replace many try/finally patterns. Instead of opening a file, wrapping everything in try, and closing in finally, you write 'with open("file.txt") as f:' and the file closes automatically when the block ends. This pattern extends to database connections, locks, and any resource that needs cleanup.

A critical rule: never use a bare 'except:' without an exception type. It catches everything, including SystemExit (raised by sys.exit()) and KeyboardInterrupt (raised by Ctrl+C), so your program can swallow its own shutdown. At minimum, use 'except Exception:', which leaves those system-level exceptions alone.

Exception types form a hierarchy: BaseException at the top, Exception below it, and ValueError, TypeError, KeyError and friends below that. Catching a parent catches all of its children, so order your except blocks from most specific to most general, or the general one will swallow the specific ones. When you catch one error and raise another, write raise NewError(...) from err to keep the original as the cause, just like new Error(msg, { cause: err }) in JS.

Quick reference

JavaScriptPythonNote
try { } catch (e) { }try: ... except E as e:except, not catch
throw new Error()raise ValueError()raise, not throw, no new
if (e instanceof X)except X:Type goes in the except clause
finally { }finally:Same concept
No equivalentelse:Runs only if no exception
try/finally for cleanupwith statementAuto-cleanup
new Error(msg, { cause })raise X(msg) from errException chaining

Side by side

JavaScript
// JavaScript
try {
  JSON.parse(badJson);
  throw new Error("Custom");
} catch (error) {
  if (error instanceof SyntaxError)
    console.log("JSON error");
} finally {
  console.log("Cleanup");
}

class ValidationError extends Error {
  constructor(field, msg) {
    super(msg);
    this.field = field;
  }
}
Python
# Python
import json
try:
    data = json.loads(bad_json)
except json.JSONDecodeError as e:   # specific first
    print(f"JSON error: {e}")
except ValueError as e:             # then more general
    print(f"Value error: {e}")
else:                              # no exception!
    print("Parse succeeded")
finally:
    print("Cleanup")

# Custom exception
class ValidationError(Exception):
    def __init__(self, field, msg):
        super().__init__(msg)
        self.field = field

# Chaining: keep the original cause
try:
    port = int("abc")
except ValueError as err:
    raise ValidationError("port", "must be a number") from err

# Context manager (replaces try/finally)
with open("file.txt") as f:
    content = f.read()
# auto-closed, even on error!

Exercise

Real Python, running in your browser

Write a function called safe_divide:

1. Takes a and b 2. If a or b are not numbers, raise TypeError 3. If b == 0, raise ZeroDivisionError 4. Otherwise return a / b 5. Call safe_divide(10, 4) inside try/except 6. Print "Result: <value>" in the else block 7. Print "Done" in the finally block
Expected output
Result: 2.5
Done

Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment