Incident brief
Division by zero
An expression divided a number by zero. PostgreSQL raises an error instead of returning infinity or an undefined result.
What lands in your log
ERROR: division by zero
In 10 seconds
- What triggers it
- Run any expression that divides by a literal or computed zero.
- Fix
- Guard the divisor with NULLIF(divisor, 0) so a zero divisor produces NULL instead of an error.
- Proof
- Reproduced on PostgreSQL 16.14 → 10 / 0 was rejected with SQLSTATE 22012. Outside a transaction block, the session was unaffected, the very next statement ran and returned a normal result.
Fix
What to do right now
Application-level steps for this error.
- Guard the divisor with NULLIF(divisor, 0) so a zero divisor produces NULL instead of an error.
- Validate the divisor in application code before sending the query, if a specific fallback value is required instead of NULL.
- Inside a transaction, remember this error aborts the transaction just like any other, see SQLSTATE 25P02.
-- NULLIF turns a zero divisor into NULL instead of raising an error
SELECT 10 / NULLIF(0, 0) AS guarded_result;For this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Division by zero (22012) is statement-local: PostgreSQL does not retain the rejected value after the statement ends. Capture the exact bound value and statement position in application/server logs, then run this targeted validation before retrying.
Validate the divisor used by the failing row
Replace the sample values with the bound numerator/denominator; NULLIF makes the zero case visible without raising.
SELECT numerator, denominator,
numerator / NULLIF(denominator, 0) AS safe_result,
denominator = 0 AS would_raise_22012
FROM (VALUES (10::numeric, 0::numeric)) v(numerator, denominator);Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual, not paraphrased.
PostgreSQL 16 Documentation, §9.18 Conditional Expressions
A constant 1/0 subexpression will usually result in a division-by-zero failure at planning time, even if it's within a CASE arm that would never be entered at run time.Read the full section on postgresql.org →
Step 1: divide by zero
PostgreSQL cannot divide by zero, so it raises SQLSTATE 22012 immediately instead of returning a result.Step 2: an unrelated statement, right after
Because this wasn't inside an explicit BEGIN/COMMIT block, the failed statement didn't poison anything, the next unrelated query ran normally and returned 5.Reproduce & verify
A real, single-session PostgreSQL reproduction
A literal transcript of SQL run against a live PostgreSQL instance in an isolated lab. The commands below are exactly what was executed.
- 1Run any expression that divides by a literal or computed zero.
- 2PostgreSQL rejects the statement with SQLSTATE 22012 instead of returning a result.
- 3Outside of an explicit transaction, the session itself is unaffected, the next statement runs normally.
One client, no schema involved: divide by zero, then run an unrelated statement to confirm the session still works.
-- No schema needed: this error only involves scalar arithmetic on literals.
SELECT 1;SELECT 10 / 0;-- outside an explicit transaction, the session is not broken by the error above
SELECT 10 / 2;What PostgreSQL actually returned
?column?
----------
1
(1 row)ERROR: division by zero ?column?
----------
5
(1 row)NULLIF(divisor, 0) was tested directly against both a zero and a non-zero divisor, proving it turns the error into a plain NULL result without changing behavior for normal values.
Without this
Above: an unguarded division by zero raises an error.
With this, tested
Below: the same division, guarded with NULLIF, returns NULL for zero and the normal result otherwise.
- A second operational test: exact SQL, raw output, measured result, and engineer notes
- Fix that looks safe but can still fail before it ever runs: exact SQL, output, and verdict
- A manual-grounded production interpretation of the lab result
Card required. Cancel before day 7 and you are not charged.
Connected
Everything this error touches
Every page this SQLSTATE connects to: the concept that explains it, the runbooks that fix it, the parameters you tune to prevent it, and the sibling errors it travels with. All real cross-references. Jump straight in, or open the full interactive map.
Verification
- Last verified
- 2026-07-15 (Docker lab, PostgreSQL 16.14)
- Verification scope
- Verified against PostgreSQL 16.14 in an isolated lab environment
- Audit status
- reviewed
Went further?
Pro unlocks the second lab proof
Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.