The 65 mistakes, and the four that repeat

Eight of the eleven sheets on this site end with a section of things that go wrong: 65 entries across Git, SQL, Docker, JavaScript, Python, React, regex and TypeScript. They were written one stack at a time, and reading them together was not the plan - but four failure modes turn up in language after language, and they are not failures of syntax. They are failures of a mental model that the syntax does nothing to correct.

This guide is the cross-stack read. It also says which three sheets have no such section and why that is informative rather than an omission.

Where the 65 entries are

Three sheets have no Common Mistakes section: Bash & Linux, HTML & CSS and Interview Prep. For Bash and HTML/CSS that is a genuine gap - both have plenty of well-known traps. For Interview Prep it is structural: the whole sheet is about how to get things right under pressure, and its Common Patterns Summary does the same job from the other direction.

The Common Mistakes sections across the eleven sheets.
SheetEntriesThe section
Git9Common Mistakes & Recovery - the only one that also covers recovery
SQL9Common Mistakes - mostly NULL semantics and index usage
Docker8Common Mistakes - layers, secrets, pinning
JavaScript8Common Mistakes - equality, this, references
Python8Common Mistakes - defaults, closures, copies
React8Common Mistakes - state identity and effects
Regular Expressions8Common Mistakes - greedy matching, escaping
TypeScript7Common Mistakes - what the type system does not do at runtime
Bash, HTML/CSS, Interview Prep0No such section

One: assignment copies a reference, not the data

This is the most widespread single misconception in the corpus - four stacks carry an entry for it, each describing the same mistake in its own vocabulary.

JavaScript: assigning an object copies the reference, and the spread operator is only a shallow copy, so nested objects stay shared. Python: list.copy(), dict.copy() and slicing are all shallow, and nested mutable objects are still shared. React: mutating a state object in place keeps the same reference, so the Object.is comparison React uses sees no change and does not re-render. TypeScript: readonly and Readonly<T> are compile-time only and are stripped during compilation, so nothing stops a mutation at runtime.

The through-line is that three of the four are not really about copying. They are about identity: whether two names point at one thing. Once that is clear, the React re-render rule and the Python nested-copy rule stop being separate facts.

JavaScript: the spread is shallow; nested objects are still shared.

Object/Array Reference Sharing · JS
// Assigning objects copies the reference, not the value

Object/Array Reference Sharing in JavaScript · Common Mistakes

Python: the same problem, with copy.deepcopy as the escape hatch.

Shallow vs Deep Copy · PY
import copy
shallow = copy.copy(obj)
deep = copy.deepcopy(obj)

Shallow vs Deep Copy in Python · Common Mistakes

React: the reference did not change, so neither did the render.

Direct State Mutation · RE
// BAD: mutating state directly
state.items.push(newItem);
setState(state);

// GOOD: create a new reference
setState({ ...state, items: [...state.items, newItem] });

Direct State Mutation in React · Common Mistakes

Two: equality is not one operation

Every language with a notion of identity has a second notion of equality, and both sheets that cover one cover the confusion between them.

JavaScript's == applies type coercion before comparing, which produces results nobody wants; the entry's rule of thumb is to always use ===, with the single exception of value == null to catch both null and undefined at once. Python's is tests identity rather than value, and the entry is explicit that it should only be used for None, True and False - the small-integer caching in CPython makes is appear to work on numbers, right up to the point where it does not.

SQL has the same shape with a third answer. NULL means unknown, so = against it is neither true nor false but unknown, which WHERE discards. That is why col = NULL matches nothing and why IS NULL exists as a separate operator - see the SQL joins guide for what that does to outer joins.

JavaScript: coercion is why == surprises people.

== vs === Confusion · JS
// Wrong: == with type coercion
// Right: === for strict comparison

== vs === Confusion in JavaScript · Common Mistakes

Python: identity versus value, and why CPython's caching hides the bug.

is vs == (Identity vs Equality) · PY
a == b  # equal values
a is b  # same object

is vs == (Identity vs Equality) in Python · Common Mistakes

Three: a closure captures the variable, not its value

Both general-purpose languages here carry an entry for the loop-closure trap, and the two entries are almost the same text with different keywords.

In JavaScript with var, every iteration shares one binding, so callbacks created in the loop all see the final value; let fixes it by creating a fresh binding per iteration. In Python, closures capture by reference and there is no block scoping to rescue you, so the idiom is a default argument - lambda i=i: ... - which evaluates at definition time.

React's version of the same thing is the stale closure: a callback inside setInterval, setTimeout or an event listener holds the state value from the render that created it, and keeps holding it. The cure is different - a dependency array or a ref rather than a new binding - but the diagnosis is identical, which is why recognising the pattern in one language transfers to the others.

JavaScript: one var binding shared by every iteration.

Closure in Loops (var trap) · JS
// Bug: var is function-scoped
// Fix: use let (block-scoped)

Closure in Loops (var trap) in JavaScript · Common Mistakes

Python: captured by reference, so the default-argument trick is the fix.

Late Binding in Closures · PY
# BAD: variable captured by reference
# GOOD: use default argument to capture value

Late Binding in Closures in Python · Common Mistakes

React: the same capture, held across renders.

Stale Closures · RE
// PROBLEM: handler captures old state value
// FIX: use updater function or ref

Stale Closures in React · Common Mistakes

Four: a destructive command with no filter

The tool sheets converge on one piece of advice: write the restriction before the verb.

SQL's entry puts it most clearly - write the WHERE clause first and build the UPDATE or DELETE around it, or run it as a SELECT with the same filter first, and wrap it in a transaction so a surprising row count can be rolled back. Git's equivalents are git reset --hard, which destroys uncommitted work with no undo, and git clean -f, where the entry recommends a -n dry run before every real invocation. Docker's is the dangling-resource cleanup, which is less dangerous but the same habit.

What makes this one worth grouping is that the fix is procedural rather than technical. Nothing in the syntax of any of these tools will stop you; the sheets all recommend the same workflow instead - preview, then commit to it.

SQL: the filter first, then the verb around it.

UPDATE / DELETE Without WHERE · SQL
-- DANGEROUS:
UPDATE users SET is_active = false;
DELETE FROM orders;

-- SAFE: always filter
UPDATE users SET is_active = false WHERE last_login < '2024-01-01';
DELETE FROM orders WHERE status = 'cancelled';

UPDATE / DELETE Without WHERE in SQL · Common Mistakes

Git: -n is a dry run, and the entry recommends it every time.

Remove Untracked Files · Git
git clean -f [-d] [-n]

Remove Untracked Files in Git · Undoing Changes

The mistakes that do not travel

Three clusters are specific to their stack and have no analogue elsewhere in the corpus, which makes them worth reading on their own terms.

TypeScript's section is almost entirely about the boundary between compile time and run time: any spreading silently through a codebase, assertions that produce no runtime check at all, readonly that disappears on compilation, structural typing matching on shape rather than on name. Nothing in a dynamically typed stack has this shape, because nothing there promises to be checked.

React's section is about a render model: effects with wrong dependency arrays, infinite re-render loops from calling setState in the render body, index keys that break when a list is reordered, and using an effect where a derived value would do. These are mistakes about a framework's lifecycle rather than about a language.

And regex's section is about an execution model - greedy quantifiers backtracking, nested quantifiers blowing up exponentially, a stateful lastIndex on a global regex. See the regex guide for the ones that come up most.

  • 65 entries, 8 of 11 sheets, between 7 and 9 entries each.
  • Four failure modes recur: shared references, equality versus identity, closures over a loop variable, and unfiltered destructive commands.
  • Three stacks have no Common Mistakes section: Bash, HTML/CSS and Interview Prep.
  • Git's is the only section that also covers recovery - see the git undo guide.
  • The entries are reachable from the sheet index as well: every section page lists its siblings.

Questions people ask

What is the most common mistake across languages?

Treating assignment as a copy. Four stacks carry an entry for it - JavaScript references, Python shallow copies, React state mutation and TypeScript's compile-time-only readonly - and all four are really about whether two names point at the same object.

Why should I use === instead of == in JavaScript?

Because == coerces types before comparing, which produces results that are hard to predict. The entry recommends === everywhere, with one exception: value == null conveniently matches both null and undefined.

Why do all my loop callbacks see the last value?

Because the closure captured the variable, not its value. In JavaScript, var gives every iteration the same binding - use let. In Python, bind it as a default argument. React's stale-closure entry is the same problem across renders.

Which sheets have no Common Mistakes section?

Bash & Linux, HTML & CSS and Interview Prep. The first two are gaps; the third is by design, since that whole sheet is about doing things correctly under interview conditions.

Is readonly enforced at runtime in TypeScript?

No. readonly, Readonly<T> and ReadonlyArray are compile-time only and are stripped during compilation. If you need a guarantee at runtime, freeze the object or copy it - the entry is explicit about this.

Where this comes from

Every code block above is rendered from this site’s own entry data at build time, with a link to the entry it came from, and every count in the prose is derived from the same file. How this cheat sheet is organized explains the structure and says what the corpus does not cover.

Keep going

More guides