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.
| Sheet | Entries | The section |
|---|---|---|
| Git | 9 | Common Mistakes & Recovery - the only one that also covers recovery |
| SQL | 9 | Common Mistakes - mostly NULL semantics and index usage |
| Docker | 8 | Common Mistakes - layers, secrets, pinning |
| JavaScript | 8 | Common Mistakes - equality, this, references |
| Python | 8 | Common Mistakes - defaults, closures, copies |
| React | 8 | Common Mistakes - state identity and effects |
| Regular Expressions | 8 | Common Mistakes - greedy matching, escaping |
| TypeScript | 7 | Common Mistakes - what the type system does not do at runtime |
| Bash, HTML/CSS, Interview Prep | 0 | No 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.
// Assigning objects copies the reference, not the valueObject/Array Reference Sharing in JavaScript · Common Mistakes
Python: the same problem, with copy.deepcopy as the escape hatch.
import copy
shallow = copy.copy(obj)
deep = copy.deepcopy(obj)React: the reference did not change, so neither did the render.
// BAD: mutating state directly
state.items.push(newItem);
setState(state);
// GOOD: create a new reference
setState({ ...state, items: [...state.items, newItem] });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.
// Wrong: == with type coercion
// Right: === for strict comparisonPython: identity versus value, and why CPython's caching hides the bug.
a == b # equal values
a is b # same objectThree: 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.
// Bug: var is function-scoped
// Fix: use let (block-scoped)Python: captured by reference, so the default-argument trick is the fix.
# BAD: variable captured by reference
# GOOD: use default argument to capture valueReact: the same capture, held across renders.
// PROBLEM: handler captures old state value
// FIX: use updater function or refFour: 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.
-- 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';Git: -n is a dry run, and the entry recommends it every time.
git clean -f [-d] [-n]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.