21000
Read PG 18 manual ↗cardinality_violation
- SQLSTATE
- 21000
- Condition name
- cardinality_violation
- Class
- Cardinality Violation
- Source macro
- ERRCODE_CARDINALITY_VIOLATION
- Evidence
- Observed at runtime in the source evidence
English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗
At a glance
21000 means that an operation received the wrong number of rows for its cardinality contract. The common user-visible case is a scalar subquery that returns more than one row. It is different from 23505: no unique index conflict is required.
Meaning
A scalar subquery used as an expression must return at most one row. PostgreSQL reports 21000 when the executor sees a second row; zero rows produce NULL. The same condition also covers command-level cases where multiple proposed rows in ON CONFLICT DO UPDATE revisit one target row, or multiple MERGE source rows match one target row. Those paths have different messages and hints, so branch on the SQLSTATE and diagnostic fields rather than on a single English string.
Diagnosis
Capture sqlstate, message_primary, hint, and the statement context. For the scalar path, inspect the subquery without discarding rows: add a predicate that reflects the intended key, or use an aggregate when “many rows become one value” is the business rule. Do not add LIMIT 1 merely to silence the error; it can choose an arbitrary row. For ON CONFLICT, deduplicate the proposed source rows under the arbiter or unique key; for MERGE, make the source-to-target join produce at most one source row per target. Inspect the actual source rows and key mapping rather than treating this as a generic duplicate-key error.
Response
In an explicit transaction, roll back the failed statement’s transaction state before issuing the corrected statement. Then make the cardinality rule explicit and retry the complete operation. For a multi-row ON CONFLICT or MERGE, retry only after the source cardinality is deterministic; repeating the same batch will reproduce the deterministic conflict. In autocommit mode the failed scalar statement left the selected sessions IDLE, but that is a property of the boundary, not a promise for a surrounding transaction or PL/pgSQL block.
Observed diagnostics
18.6 (Homebrew) / latest:SQLSTATE 21000; primary more than one row returned by a subquery used as an expression; status_after_error IDLE.
10.21 (Debian 10.21-1.pgdg90+1) / pg10:SQLSTATE 21000; primary more than one row returned by a subquery used as an expression; status_after_error IDLE.
Representative case
The runner reads these statements from verify/cases/21000/snippets.json (SHA-256 6d820e94518ffca97f407956fdc2df104d47b14263d3117ff59dbc4409774dc2) and qualifies the temporary table names; the complete setup, assertions, and cleanup are in the case export.
-- create
CREATE TABLE source_rows(id integer PRIMARY KEY);
-- seed
INSERT INTO source_rows VALUES (1), (2);
-- trigger
SELECT (SELECT id FROM source_rows ORDER BY id) AS only_id;
-- valid
SELECT (SELECT id FROM source_rows WHERE id = 1) AS only_id;
The SQLSTATE, diagnostic, transaction-state, and repair assertions for this excerpt are produced from the shared registry; structured evidence · case export.
Authored evidence IDs: identity, scalar-subquery, dml-conflict, runtime. Selected runtime records: runtime.21000-batch1-latest-20260909.latest, runtime.21000-batch1-pg10-20260909.pg10.
Versions
The locked catalogue observes the condition by 7.4 and in every listed 9.0–18.6 formal snapshot. The fixed source evidence confirms the 18.6 scalar, ON CONFLICT, and MERGE paths; the selected runtime case covers only a scalar subquery on 18.6 and 10.21.
Sources
src.errcodes.18.6(SHA-2566e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)src.calls.REL_18_6(SHA-2569ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)src.nodeSubplan.18.6(SHA-256c356a9812691f875974c1f476efa987015ba19e70a4be833a43b692f3554dc47)src.nodeModifyTable.18.6(SHA-2560fc3cb180b3443f216142954e43d8ed5f84713d75094ce8cd2785ad8f604bd68)doc.syntax.18.6(SHA-256449b0c500fccca068d0f8a1db2a5ebb5430eb83e33f12c6cb310a01a7437b635) · official documentation
Source evidence
Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.
21000 is the cardinality_violation condition in Class 21.
Method: Read the fixed errcodes.txt row and macro mapping.
Limits: This identifies the protocol condition; it does not select one particular SQL operation.
A scalar subquery used as an expression must yield at most one row; the executor reports 21000 when it produces a second row.
Method: Trace ERRCODE_CARDINALITY_VIOLATION and the fixed scalar-subquery documentation.
Limits: A scalar subquery returning zero rows yields NULL; the error is the more-than-one-row case.
ON CONFLICT DO UPDATE and MERGE can use 21000 when one command would affect the same target row a second time.
Method: Read the separate nodeModifyTable report groups and their hints.
Limits: This is a command-level cardinality conflict, not a generic duplicate-key error.
The selected scalar-subquery case returned 21000 on PostgreSQL 18.6 and 10.21, remained usable in autocommit mode, and succeeded after a one-row predicate.
Method: Compare the selected summaries, raw outputs, and shared snippet registry.
Limits: The run covers one scalar-subquery path; it does not validate ON CONFLICT, MERGE, PL/pgSQL, dblink, or materialized-view paths.
runtime.21000-batch1-latest-20260909.latest runtime.21000-batch1-pg10-20260909.pg10
- src/backend/utils/errcodes.txt · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 raw/calls/REL_18_6.jsonl· ·- src/backend/executor/nodeSubplan.c · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 - src/backend/executor/nodeModifyTable.c · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 - doc/src/sgml/syntax.sgml · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7
Message templates
ERROR · message.scalar-subquery
Primary
more than one row returned by a subquery used as an expression
This is the scalar-subquery template; other 21000 paths have different templates.
ERROR · dml-second-target
Primary
%s command cannot affect row a second time
Hint
Ensure that no rows proposed for insertion within the same command have duplicate constrained values. / Ensure that not more than one source row matches any one target row.
The %s substitution is ON CONFLICT DO UPDATE or MERGE; the hint branch is command-specific.
Reproduction & repair cases
scalar_subquery_cardinality · PG 10, 18
Preconditions
- A disposable table contains two source rows
- The scalar subquery is expected to return at most one row
Trigger: Use a two-row subquery in a scalar expression.
Expected assertions
- SQLSTATE is 21000
- The connection remains usable after the autocommit error
- A one-row predicate succeeds afterward
Repair: Make the scalar relation one row by predicate, aggregation, or an explicit application rule; do not add LIMIT without defining which row is correct.
Cleanup: Drop the case schema with an owner connection.
Recorded runtime evidence
18.6 (Homebrew) · passed
Run: 21000-batch1-latest-20260909
{
"primary": "more than one row returned by a subquery used as an expression",
"sqlstate": "21000",
"valid_result": 1,
"status_after_error": "IDLE"
}10.21 (Debian 10.21-1.pgdg90+1) · passed
Run: 21000-batch1-pg10-20260909
{
"primary": "more than one row returned by a subquery used as an expression",
"sqlstate": "21000",
"valid_result": 1,
"status_after_error": "IDLE"
}Definition snapshot: english-manuals:67fe195d9c0576f02f6e36982ee… · English manual source