Skip to content

22004 — null_value_not_allowed

Source-backed reference for PostgreSQL SQLSTATE 22004.

22004

At a glance

22004 is null_value_not_allowed. The fixed table-function path rejects a null namespace URI; many other extensions and core functions use the same condition for different null contracts.

Field Value
SQLSTATE 22004
Condition null_value_not_allowed
Status active
Known present by 7.4
Locked snapshots 9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3
Macros ERRCODE_NULL_VALUE_NOT_ALLOWED
Aliases

The shared case supplies a NULL XMLTABLE namespace URI, then repeats the table-function call with URI u and a matching XML row. Send the two SELECT statements separately; the first is expected to fail before the repaired call runs. The runner controls the session and cleanup.

SELECT * FROM XMLTABLE(XMLNAMESPACES (NULL AS p), '/p:row' PASSING '<p:row xmlns:p="u"/>' COLUMNS x text PATH 'p:x');
SELECT count(*) FROM XMLTABLE(XMLNAMESPACES ('u' AS p), '/p:row' PASSING '<p:row xmlns:p="u"><p:x>ok</p:x></p:row>' COLUMNS x text PATH 'p:x');

Calibration observed the table-function namespace URI path: a NULL namespace reported namespace URI must not be null; a valid URI returned one XMLTABLE row, and both runner autocommit sessions returned to IDLE.

Messages

The namespace guard raises ERROR with primary namespace URI must not be null, with no separate DETAIL or HINT. The table-function executor module also has distinct ERROR guards for a null row-filter expression and a null column-filter expression (with a column-name DETAIL). Its output-column guard is narrower: after the XMLTABLE output column is marked NOT NULL, the value is obtained and any DEFAULT expression is applied; only when it is still NULL does it raise null is not allowed in column "%s". That output-column condition is distinct from an ordinary NULL result or a separate 23502 constraint error. The selected runtime observed only the namespace message.

Meaning

22004 is a NULL contract failure. In the fixed nodeTableFuncscan.c path, the rejected value is a namespace URI used by a table function: namespace URI must not be null. The same condition name can be selected by other functions, so a NULL function argument, a NULL result from a STRICT function, and a table column declared NOT NULL are different investigations. A normal SQL NULL result is not evidence of 22004; use the actual SQLSTATE and diagnostic fields.

Diagnosis

Use the full message, routine, context, and object fields to identify which parameter or descriptor was NULL. For the confirmed table-function path, inspect the namespace URI expression and the table-function XML/row description that supplied it. A plain NULL input or a STRICT function returning NULL does not by itself indicate this condition. If the response instead names a column constraint, use its actual SQLSTATE and constraint fields; do not relabel a column NOT NULL violation as 22004.

Response

Fix the function parameter or descriptor that the message identifies, or change the table-function definition so the namespace URI contract is satisfied. Preserve intentional SQL NULLs where the API permits them; replacing every NULL with an empty string can change XML or query semantics. The frozen case used autocommit, so the failed statement left the session IDLE; inside an explicit transaction, roll back the transaction or roll back to a pre-existing savepoint before continuing. Validate the corrected call before repeating a write.

Versions

The locked catalogue records this condition from 7.4 in the listed formal snapshots and 19beta3; fixed source coverage is PostgreSQL 18.6.

22000 for other Data Exception paths, 22002 for the ECPG indicator-variable condition, and 23502 when the actual response is a not-null-constraint violation.

Sources

The confirmed table-function check is nodeTableFuncscan.c#L368-L370; the neighboring filter/output guards are in nodeTableFuncscan.c#L380-L419 and nodeTableFuncscan.c#L494-L508. The structured evidence record pins these paths and keeps other NULL contracts conditional.