Resource never released
Acquired on every path, released on only some.
What it looks like
- A lock, handle, timer or subscription released at the end of a function that has an early return.
- A cleanup that lives in the happy path rather than in a
finally. - An interval started in a branch and cleared in another.
Why it survives review
The happy path releases correctly, and the happy path is what gets exercised. The leak only accumulates on the error path or the early-return path — slowly, invisibly, until the process runs out of whatever it was leaking, at which point the symptom is nowhere near the cause.
How to see it
- For every acquire, find the release, then check *every* path between them — including the ones that throw.
- Cleanup belongs in
finally, or in the disposal half of a scoped helper. Cleanup as the last statement of a function is cleanup that early returns skip. - An early return added to a function that holds a resource is a leak until proven otherwise.
A minimal pair
Correct
const handle = acquire();
try {
return read(handle);
} finally {
handle.close();
}
Defective
const handle = acquire();
if (!handle.ready) return null;
const value = read(handle);
handle.close();
return value;
A handle that is not ready is never closed, and each call leaks one.
Practise it
1 diff in the corpus carry this class. They are not listed, because knowing which diff contains what would make finding it a comprehension question about this page.
Go to the exercises