Incident brief
Column must appear in GROUP BY
A non-aggregated column in the SELECT list of a grouped query must appear in GROUP BY or be wrapped in an aggregate; otherwise PostgreSQL raises this grouping error.
What lands in your log
ERROR: column "sales_line.amount" must appear in the GROUP BY clause or be used in an aggregate function
In 10 seconds
- What triggers it
- Write a GROUP BY query that selects a column which is neither grouped nor aggregated.
- Fix
- Wrap the column in an aggregate (SUM, MAX, ...).
- Proof
- Reproduced on PostgreSQL 18.4 → A single query reproduces SQLSTATE 42803; the ungrouped column is rejected and the LINE points at it.
Fix
What to do right now
Application-level steps for this error.
- Wrap the column in an aggregate (SUM, MAX, ...).
- Or add the column to the GROUP BY clause if you meant to group by it.
-- Aggregate the column (or add it to GROUP BY).
SELECT customer_id, sum(amount) FROM sales_line GROUP BY customer_id;For this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Column must appear in GROUP BY is fixed in the statement text. PostgreSQL stores no failed parse tree, so use the error POSITION against the exact SQL sent by the driver and inspect real column/function names.
Candidate columns on the referenced relations
Replace the relation array with the tables/aliases in the failing statement.
SELECT attrelid::regclass AS table_name, attnum, attname,
format_type(atttypid, atttypmod) AS data_type
FROM pg_attribute
WHERE attrelid = ANY (ARRAY[
to_regclass('<first_relation>'),
to_regclass('<second_relation>')
]::regclass[])
AND attnum > 0 AND NOT attisdropped
ORDER BY attname, table_name;Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual, not paraphrased.
PostgreSQL 18 Documentation, Appendix A. PostgreSQL Error Codes (Table A.1, Class 42, Syntax Error or Access Rule Violation)
42803 → grouping_errorRead the full section on postgresql.org →
Selecting an ungrouped, unaggregated column
amount is neither grouped nor aggregated, so PostgreSQL raises 'column sales_line.amount must appear in the GROUP BY clause or be used in an aggregate function'.The session continues normally
The GROUP BY check failed at parse time outside a transaction block, so the session has nothing to undo before its next statement.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.
- 1Write a GROUP BY query that selects a column which is neither grouped nor aggregated.
- 2PostgreSQL checks that every output column is determined by the grouping.
- 3The ungrouped, unaggregated column aborts the statement with SQLSTATE 42803.
A per-customer total selected the raw amount alongside GROUP BY customer_id, and the query would not run until amount was aggregated.
CREATE TABLE sales_line(customer_id int, amount numeric);
INSERT INTO sales_line VALUES (1, 20),(1, 30);SELECT customer_id, amount FROM sales_line GROUP BY customer_id;SELECT 'ok' AS session_after_error;What PostgreSQL actually returned
CREATE TABLE
INSERT 0 2ERROR: column "sales_line.amount" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT customer_id, amount FROM sales_line GROUP BY customer...
^ session_after_error
---------------------
ok
(1 row)The same grouped query runs once the column is aggregated.
Without this
Before: the raw column aborts
With this, tested
After: SUM(amount) groups cleanly
- A second operational test: exact SQL, raw output, measured result, and engineer notes
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-24 (isolated lab, PostgreSQL 18.4)
- Verification scope
- Verified against PostgreSQL 18.4 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.