# 22004 — null_value_not_allowed

> Source-backed reference for PostgreSQL SQLSTATE 22004.
---

# 22004

## At a glance {#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.

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| 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 | `—` |

<!-- source facts: data/errcodes/22004.json -->
<!-- END SQLSTATE FACTS -->

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.

<!-- BEGIN SQLSTATE SNIPPET: xmltable_null_namespace -->
```sql
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');
```
<!-- END SQLSTATE SNIPPET -->

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 {#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 {#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 {#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 {#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 {#versions}

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

## Related {#related}

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

## Sources {#sources}

The confirmed table-function check is [`nodeTableFuncscan.c#L368-L370`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeTableFuncscan.c#L368-L370); the neighboring filter/output guards are in [`nodeTableFuncscan.c#L380-L419`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeTableFuncscan.c#L380-L419) and [`nodeTableFuncscan.c#L494-L508`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeTableFuncscan.c#L494-L508). The structured [evidence record](../data/evidence/22004.json) pins these paths and keeps other NULL contracts conditional.
