Internal error codes triggered by regression tests and user queries, take 2
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253558psql -h localhost -U postgresBuilt from patchset v1 (message #1), August 26, 2026 at 02:16 PM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t253558_1 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t253558_1 && git checkout t253558_1Patchset v1 (message #1) is on t253558_1
Hello Michael,
Please take a look at the follow-up to [0]/messages/by-id/aozYob22-UJ8CWzk@paquier.xyz. I've prepared a patch to
assign error codes for errors reached by the following queries:
1)
create table notnull_tbl_fail (a serial constraint foo not null constraint bar not null); -- from constraints.sql
ERROR: XX000: conflicting not-null constraint names "foo" and "bar"
LOCATION: transformColumnDefinition, parse_utilcmd.c:800
ERRCODE_INVALID_TABLE_DEFINITION
2)
SELECT satisfies_hash_partition(0, 4, 0, NULL); -- from hash_part.sql
ERROR: XX000: could not open relation with OID 0
LOCATION: relation_open, relation.c:62
ERRCODE_INVALID_PARAMETER_VALUE (also modified try_relation_open() for consistency)
3)
SELECT COUNT(*) = 0 AS ok FROM pg_shmem_allocations_numa; -- from numa.sql
ERROR: XX000: libnuma initialization failed or NUMA is not supported on this platform
LOCATION: pg_get_shmem_allocations_numa, shmem.c:1122
ERRCODE_FEATURE_NOT_SUPPORTED
4)
create table idxpart (a int) partition by range (a);
create table idxpart0 (like idxpart);
alter table idxpart0 add unique (a);
alter table idxpart attach partition idxpart0 default;
alter table only idxpart add primary key (a); -- from indexing.sql
ERROR: XX000: column "a" of table "idxpart0" is not marked NOT NULL
LOCATION: ATPrepAddPrimaryKey, tablecmds.c:9695
ERRCODE_INVALID_TABLE_DEFINITION
5)
CREATE FUNCTION test_pglz_compress(bytea)
RETURNS bytea
AS '.../src/test/regress/regress.so' LANGUAGE C STRICT;
CREATE FUNCTION test_pglz_decompress(bytea, int4, bool)
RETURNS bytea
AS '.../src/test/regress/regress.so' LANGUAGE C STRICT;
SELECT test_pglz_decompress(test_pglz_compress(
decode(repeat('abcd', 100), 'escape')), 500, true); -- compression_pglz.sql:
ERROR: XX000: pglz_decompress failed
LOCATION: test_pglz_decompress, regress.c:1497
ERRCODE_DATA_CORRUPTED (like for "compressed pglz data is corrupt")
With these changes plus
v1-0001-Report-specific-SQLSTATEs-for-stats-restore-error.patch from [1]
applied, `make check` passes without XX000 errors for me. Tested with:
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -498,6 +498,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
elevel = edata->elevel;
+Assert(!(elevel == ERROR && edata->sqlerrcode == ERRCODE_INTERNAL_ERROR));
/*
* Do processing in ErrorContext, which we hope has enough reserved space
* to report an error.
There are also other internal errors produced during `make check-world`,
but I think they should be considered separately, as most of them are too
generic or really internal, like "cache lookup failed for relation xxx"
triggered by intra-grant-inplace.
Besides the above, I've included in the patch assigning error codes to
errors reported by Justin Pryzby at [2]/messages/by-id/20230213135053.GZ1653@telsasoft.com, except for the dubious
amvalidate() and pg_read_file with parse_weight (both are already fixed):
6)
select unknownin('');
ERROR: XX000: failed to find conversion function from unknown to text
LOCATION: coerce_type, parse_coerce.c:544
ERRCODE_CANNOT_COERCE (used by other functions in parse_coerce.c)
7)
SELECT pg_catalog.interval( '12 seconds'::interval ,3);
ERROR: XX000: unrecognized interval typmod: 3
LOCATION: AdjustIntervalForTypmod, timestamp.c:1492
ERRCODE_INVALID_PARAMETER_VALUE (like below in the same function)
8)
SELECT pg_describe_object(1,0,1);
ERROR: XX000: unsupported object class: 1
LOCATION: getObjectDescription, objectaddress.c:4317
ERRCODE_WRONG_OBJECT_TYPE
9)
SELECT acldefault('a',0);
ERROR: XX000: unrecognized object type abbreviation: a
LOCATION: acldefault_sql, acl.c:999
ERRCODE_WRONG_OBJECT_TYPE
10)
select float8_regr_intercept(ARRAY[1]/messages/by-id/CAHGQGwHZLiLa9iM7NAiugp1B7CumN94=YBeho9t=qKJMnTGwMQ@mail.gmail.com);
ERROR: XX000: float8_regr_intercept: expected 8-element float8 array
LOCATION: check_float8_array, float.c:2985
ERRCODE_INVALID_PARAMETER_VALUE
A couple of cases I reported before:
11)
do $$ #print_strict_params XXX $$;
ERROR: XX000: unrecognized print_strict_params option xxx
CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 1
LOCATION: plpgsql_yyparse, pl_gram.y:396
ERRCODE_SYNTAX_ERROR
12)
select pg_catalog.range_in('', 23, 0);
ERROR: XX000: type 23 is not a range type
LOCATION: get_range_io_data, rangetypes.c:339
ERRCODE_DATATYPE_MISMATCH (like for "data type %s is not an array type")
[0]: /messages/by-id/aozYob22-UJ8CWzk@paquier.xyz
[1]: /messages/by-id/CAHGQGwHZLiLa9iM7NAiugp1B7CumN94=YBeho9t=qKJMnTGwMQ@mail.gmail.com
[2]: /messages/by-id/20230213135053.GZ1653@telsasoft.com
Best regards,
Alexander
Alexander Lakhin <exclusion@gmail.com> writes:
Please take a look at the follow-up to [0]. I've prepared a patch to
assign error codes for errors reached by the following queries:
I'm not on board with these proposed changes to [try_]relation_open.
They're basically band-aids rather than fixes of the root problems.
That is, if someone passes OID 0 to relation_open, that IS an internal
bug; labeling it otherwise is a lie and does nothing to fix the real
problem at the caller level.
A lot of these other proposed changes have the same whiff of blaming
the messenger rather than looking for the root cause.
regards, tom lane
Hi,
On 2026-08-26 10:26:58 -0400, Tom Lane wrote:
Alexander Lakhin <exclusion@gmail.com> writes:
Please take a look at the follow-up to [0]. I've prepared a patch to
assign error codes for errors reached by the following queries:I'm not on board with these proposed changes to [try_]relation_open.
They're basically band-aids rather than fixes of the root problems.
That is, if someone passes OID 0 to relation_open, that IS an internal
bug; labeling it otherwise is a lie and does nothing to fix the real
problem at the caller level.A lot of these other proposed changes have the same whiff of blaming
the messenger rather than looking for the root cause.
+1.
This is triply true for stuff like test_pglz_decompress() - this isn't
something that should be translated or that we care about having a proper
error code assigned.
Most of these would make it *harder* to find unexpected scenarios, i.e. the
patch would make the situation strictly worse. It's useful to be able to
search production logs for internal errors. As-is the patch would break that.
Looking through them, the ones that look relatively clearly to be worth
turning into ereports seem to be:
- pg_get_shmem_allocations_numa() - there's really no reason for this to be an
elog(), it's obviously expected to be reached on a bunch of platforms / configurations
- transformColumnDefinition() - that's clearly reachable with plain DDL,
without representing a bug in an upper layer.
I'm a bit on the fence about the one get_range_io_data(). We could catch that
on a higher layer, but
a) that'd be duplicated code,
b) other errors, like not having send/receive are already handled in
get_range_io_data, with ereports()
c) for e.g. composites, we handle the same problem centrally, rather than have
checks in record_in() etc (the check is in lookup_rowtype_tupdesc_internal).
Looking at this reminds me of something orthogonal: Isn't it pretty weird that
we have a per-type cache, with lots of information about the types, but don't
have the in/out/send/recv cached in there, but do cache EQ/LT/.. etc?
Greetings,
Andres Freund