Incident brief
Null value not allowed
A PL/pgSQL variable declared NOT NULL was assigned a null value. PostgreSQL rejected the assignment instead of silently storing null.
What lands in your log
ERROR: null value cannot be assigned to variable "v" declared NOT NULL
In 10 seconds
- What triggers it
- Declare a PL/pgSQL variable with NOT NULL and a default value.
- Fix
- Don't assign NULL to a variable declared NOT NULL, check for null first with an IF, or use COALESCE on the source value before assigning.
- Proof
- Reproduced on PostgreSQL 16.14 → Assigning NULL to a NOT NULL PL/pgSQL variable was rejected with SQLSTATE 22004. The session was unaffected afterward.
Fix
What to do right now
Application-level steps for this error.
- Don't assign NULL to a variable declared NOT NULL, check for null first with an IF, or use COALESCE on the source value before assigning.
- If null is a valid outcome, drop NOT NULL from the declaration instead of fighting it.
DO $$
DECLARE
v int NOT NULL := 5;
BEGIN
v := coalesce(NULL::int, 0);
RAISE NOTICE 'v = %', v;
END $$;For this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Null value not allowed (22004) 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.
Surface a NULL before assigning it to a NOT NULL PL/pgSQL variable
Validate the specific value/shape that can raise this SQLSTATE.
SELECT candidate,
candidate IS NULL AS would_raise_22004,
coalesce(candidate, 0) AS guarded_value
FROM (VALUES (NULL::int)) v(candidate);Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual, not paraphrased.
PostgreSQL 16 Documentation, PL/pgSQL Declarations (43.3)
If NOT NULL is specified, an assignment of a null value results in a run-time error.Read the full section on postgresql.org →
The rejected assignment
Per the manual, a NOT NULL PL/pgSQL variable rejects any assignment of null with a run-time error rather than silently storing it.Confirming the session still works
The PL/pgSQL block that assigned null to a NOT NULL variable is what failed, the calling session itself is untouched, so its next statement runs normally.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.
- 1Declare a PL/pgSQL variable with NOT NULL and a default value.
- 2Assign it NULL later in the block.
- 3SQLSTATE 22004 is reported; the block aborts.
One client: a DO block declares a NOT NULL variable, then assigns it NULL.
-- No table needed: this is a pure PL/pgSQL variable rule.
SELECT 'no schema required' AS setup_note;DO $$
DECLARE
v int NOT NULL := 5;
BEGIN
v := NULL;
END $$;SELECT 1 AS session_still_alive;What PostgreSQL actually returned
setup_note
--------------------
no schema required
(1 row)ERROR: null value cannot be assigned to variable "v" declared NOT NULL
CONTEXT: PL/pgSQL function inline_code_block line 5 at assignment session_still_alive
---------------------
1
(1 row)The deeper lab audit for this error
- Fix that catches the wrong exception name: 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-16 (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.