XX000 — internal_error
At a glance
XX000 is the internal_error condition in Class XX, Internal Error. The PostgreSQL source directory describes this class as covering “can’t-happen” conditions and software bugs. It is a generic diagnostic boundary, not a claim that a database is corrupt.
The code also has a mechanical default. In the error stack initializer, an ERROR or higher level with no later explicit code starts as ERRCODE_INTERNAL_ERROR; WARNING starts as ERRCODE_WARNING (01000); and a level below WARNING starts with 00000 unless it supplies its own code. An explicit errcode() can select another SQLSTATE. Therefore, XX000 can arise from a default elog(ERROR, ...) path or from a deliberate internal-error report.
Severity and connection consequences are path-dependent. ERROR, FATAL, and PANIC are different protocol severities; an explicit XX000 can even accompany a NOTICE in extension test code. Read the severity, transaction status, connection state, source location, and complete diagnostic together.
The representative case internal_error_safety_boundary is source-only. It is recorded as not_applicable on PostgreSQL 18.6 and 10.21 because forcing internal corruption or a fault would cross the safe disposable SQL boundary. No fabricated RAISE is presented as a natural internal server failure.
| Field | Value |
|---|---|
| SQLSTATE | XX000 |
| Condition | internal_error |
| 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_INTERNAL_ERROR |
| Aliases | — |
Meaning and trigger paths
The 18.6 definition is XX000 E ERRCODE_INTERNAL_ERROR internal_error under Class XX. The class comment is intentionally broad. More specific codes exist for data corruption (XX001) and index corruption (XX002); choosing XX000 does not silently upgrade a generic internal report into either diagnosis.
There are two source patterns to distinguish:
- Default internal code. A backend path calls
elog(ERROR, ...)or otherwise reachesereport(ERROR, ...)without an explicit SQLSTATE.elog.cinitializes that error asXX000. The message and source function still identify the subsystem. - Explicit internal code. A path calls
errcode(ERRCODE_INTERNAL_ERROR)because an invariant or an operating-system/service result was considered impossible or unusable. In 18.6, examples include btree rechecking that cannot re-find a tuple, an invalid dynamic shared-memory control segment, an attempt to redefine a non-placeholder configuration parameter, and failure to obtain strong random bytes for UUID generation.
The explicit code does not force one severity. The shared-memory path reports FATAL, while the btree, GUC, and UUID examples report ERROR. A test access-control hook intentionally reports NOTICE with ERRCODE_INTERNAL_ERROR, showing that SQLSTATE and severity are separate fields. That hook is a source example, not evidence that ordinary production notices indicate an internal failure.
Messages and diagnostics
XX000 has no universal primary message. Representative source templates include:
failed to re-find tuple within index "%s", with a hint that a non-immutable index expression may be responsible (nbtinsert.c).dynamic shared memory control segment is not validon theFATALinitialization path (dsm.c).attempt to redefine parameter "%s"(guc.c) andcould not generate random values(uuid.c).invalid page pd_lower %u pd_upper %u pd_special %ufrom a defaultelog(ERROR, ...)path (bufmask.c); the default mapping suppliesXX000when no explicit code replaces it.
Treat these as path-specific diagnostic templates. Record SQLSTATE, both severity fields, primary message, detail, hint, context, source file, function, line, backend PID, database, and server version. Localized text and template wording can vary; the source path and structured fields are more stable than a message substring.
Diagnosis
Preserve the complete client error and the matching server log record before retrying or restarting anything. First classify the protocol severity:
- An
ERRORnormally aborts the current explicit transaction but leaves the backend connection available after rollback. - A
FATALends the backend session; the client must establish a new connection before continuing. - A
PANICis a server-wide emergency path whose process and connection effects must be confirmed from the server log and supervision state. - A
WARNINGorNOTICEwith an explicitXX000has different control flow and does not by itself prove an internal failure or abort a transaction.
Then group the event by source function and subsystem. Check for a preceding I/O, memory, extension, index, configuration, or concurrency failure; compare the exact server build and fixed source revision; and look for repeated occurrences. Use read-only catalog, index, or page checks only when the diagnostic points to them. Do not infer corruption from the class name alone, and do not replace the message with a hand-written RAISE EXCEPTION test: that would exercise P0001 by default rather than the server’s internal path.
Response
Follow the severity and the subsystem. Roll back an ERROR transaction before issuing unrelated commands; reconnect after FATAL; and follow the server’s restart and incident procedure after PANIC. Do not blindly retry an internal-error operation, especially when the source points to an invariant, storage, index, or shared-memory boundary.
Collect the server version, exact SQL, backend and server logs, source location, relation or object identity, and recent configuration or extension changes. If the evidence points to corruption, stop writes as appropriate for the incident, preserve a copy or snapshot, and use the documented PostgreSQL recovery and support process. If it points to a deterministic software or extension defect without corruption evidence, isolate the reproducer and compare supported versions. The correct response is determined by that evidence, not by XX000 alone.
Versions
The catalogue records XX000 in the locked 7.4–8.4.22 pre-9.0 formal sources, every formal snapshot from 9.0.23 through 18.6, and the 19 Beta 3 preview. The same-tag REL8_1_4 errcodes.sgml table already lists XX000 as internal_error, confirming that condition-name observation by 8.1.4. The class title is Internal Error (PostgreSQL-specific error class) in the 9.0 header view and changes to Internal Error in the 9.1 text definition. Candidate source gaps remain for 7.0–7.3; these are observed catalogue boundaries, not exact implementation introduction dates.
The fixed 18.6 source commit is 724edf9bde9d356724ad384a2e196edc3c9f80f7. The default severity-to-code mapping and the source paths above are 18.6 evidence. No deterministic safe SQL trigger was accepted for the representative runtime case, so the runtime status remains not_applicable on both targets.
Related
XX001 — data_corrupted and XX002 — index_corrupted are more specific corruption conditions. P0001 — raise_exception is the normal default for an explicit PL/pgSQL RAISE EXCEPTION without a code. 57P01 — admin_shutdown is a server-connection event with a different class and response. 25P02 — in_failed_sql_transaction is a follow-on transaction state after an earlier error, not a synonym for XX000.
Sources
The structured evidence is recorded in the public evidence JSON. Source records are pinned to PostgreSQL commit 724edf9bde9d356724ad384a2e196edc3c9f80f7; runtime records retain the exact source-only case ID and both target summaries.
src.errcodes.18.6—errcodes.txtsrc.elog.18.6—elog.csrc.nbtinsert.18.6,src.dsm.18.6,src.guc.18.6,src.uuid.18.6, andsrc.bufmask.18.6— source-confirmed internal pathssrc.oat-hooks.18.6— explicit internal code atNOTICEdoc.protocol.18— Error and Notice Message Fields