# XX000 — internal_error（内部错误）

> PostgreSQL 使用 SQLSTATE XX000 表示内部错误路径，也把没有显式代码的 ERROR 默认映射到这里。应保留完整诊断并调查具体子系统；XX000 本身不能证明数据损坏。
---

## 速览 {#at-a-glance}

`XX000` 是类别 XX `Internal Error` 中的 `internal_error` 条件。PostgreSQL 源码目录把这个类别描述为“本不应发生”的条件和软件缺陷。它是通用的诊断边界，不能据此断言数据库已经损坏。

这个代码也有机械的默认来源。在错误栈初始化时，没有后续显式代码的 `ERROR` 或更高级别会先使用 `ERRCODE_INTERNAL_ERROR`；`WARNING` 级别从 `ERRCODE_WARNING`（`01000`）开始；低于 `WARNING` 的级别若没有自己的代码则从 `00000` 开始。显式 `errcode()` 可以选择其他 SQLSTATE。因此，`XX000` 可能来自没有显式 SQLSTATE 的默认 `elog(ERROR, ...)` 路径，也可能来自主动报告内部错误的路径。

严重级别和连接后果取决于具体路径。`ERROR`、`FATAL` 和 `PANIC` 是不同的协议严重级别；扩展测试代码甚至可以在 `NOTICE` 中显式携带 `XX000`。应把严重级别、事务状态、连接状态、源码位置和完整诊断放在一起读取。

代表性案例 `internal_error_safety_boundary` 只做源码核验，未实测自然触发路径。由于强行制造内部损坏或故障会越过安全的临时数据库边界，PostgreSQL 18.6 和 10.21 上均记录为 `not_applicable`，也没有用手写 `RAISE` 冒充服务器内部失败。

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

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `XX000` |
| 条件名 | `internal_error` |
| 状态 | `有效` |
| 已知存在于 | `7.4` |
| 锁定快照 | `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` |
| 宏 | `ERRCODE_INTERNAL_ERROR` |
| 别名 | `—` |

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

## 含义与触发路径 {#meaning}

18.6 的定义是在类别 XX 下的 `XX000 E ERRCODE_INTERNAL_ERROR internal_error`。这个类别注释有意保持宽泛。对于数据损坏（`XX001`）和索引损坏（`XX002`）还有更具体的代码；选用 `XX000` 不会自动把通用内部报文升级成这两种诊断。

需要区分两种源码模式：

1. **默认内部代码。** 后端路径调用没有显式 SQLSTATE 的 `elog(ERROR, ...)`，或以同样方式到达 `ereport(ERROR, ...)`。`elog.c` 会把这个错误初始化为 `XX000`，但报文和源码函数仍能指出所属子系统。
2. **显式内部代码。** 某条路径调用 `errcode(ERRCODE_INTERNAL_ERROR)`，因为某个不变量或操作系统/服务结果被视为不可能或不可用。18.6 中的例子包括 B-tree 重检时无法重新找到索引元组、动态共享内存控制段无效、尝试重新定义非占位配置参数，以及 UUID 生成无法取得强随机字节。

显式代码不会强制唯一的严重级别。共享内存路径报告 `FATAL`，而 B-tree、GUC 和 UUID 例子报告 `ERROR`。一个访问控制测试钩子还会在 `NOTICE` 中显式报告 `ERRCODE_INTERNAL_ERROR`，说明 SQLSTATE 与严重级别是分开的字段。这个钩子只是源码例子，不是普通生产提示表示内部故障的证据。

## 报文与诊断 {#messages}

`XX000` 没有统一的主报文。源码中可见的代表性模板包括：

- `failed to re-find tuple within index "%s"`，并提示索引表达式可能不是不可变的（`nbtinsert.c`）。
- `dynamic shared memory control segment is not valid`，出现在 `FATAL` 初始化路径（`dsm.c`）。
- `attempt to redefine parameter "%s"`（`guc.c`）和 `could not generate random values`（`uuid.c`）。
- 默认 `elog(ERROR, ...)` 路径中的 `invalid page pd_lower %u pd_upper %u pd_special %u`（`bufmask.c`）；没有其他显式代码替换时，默认映射会提供 `XX000`。

这些都是具体路径的诊断模板。应记录 SQLSTATE、两种严重级别字段、主报文、详细信息、提示、上下文、源码文件、函数、行号、后端 PID、数据库和服务器版本。本地化文本和模板措辞可能变化；源码路径和结构化字段比报文子串更稳定。

## 诊断 {#diagnosis}

在重试或重启前保留完整的客户端错误和对应服务器日志。先按协议严重级别分类：

- `ERROR` 通常会中止当前显式事务，但回滚后后端连接仍可使用。
- `FATAL` 会结束后端会话，客户端需要建立新连接才能继续。
- `PANIC` 是影响服务器的紧急路径，进程和连接后果必须根据服务器日志和进程监管状态确认。
- 显式携带 `XX000` 的 `WARNING` 或 `NOTICE` 具有不同控制流，单凭它既不能证明内部故障，也不能断言事务中止。

随后按源码函数和子系统归类。检查是否有先发生的 I/O、内存、扩展、索引、配置或并发故障；比对确切服务器构建和固定源码版本；寻找是否重复出现。只有当诊断指向相关对象时，才使用只读的目录、索引或页面检查。不能仅凭类别名推断损坏，也不要用手写 `RAISE EXCEPTION` 来制造复现：那默认测试的是 `P0001`，不是服务器内部路径。

## 处理 {#response}

按照严重级别和子系统处理。`ERROR` 要先回滚事务再发无关命令；`FATAL` 后重新建立连接；`PANIC` 后遵循服务器重启和事故流程。内部错误若源码指向不变量、存储、索引或共享内存边界，不应盲目重试。

收集服务器版本、确切 SQL、后端和服务器日志、源码位置、关系对象或其他对象身份，以及近期配置和扩展变化。如果证据指向损坏，应根据事故流程在适当时停止写入，保留副本或快照，并使用 PostgreSQL 文档化的恢复与支持流程。如果证据指向没有损坏迹象的软件或扩展缺陷，则隔离可复现条件并比较受支持的版本。正确处理取决于这些证据，而不是 `XX000` 本身。

## 版本 {#versions}

目录记录 `XX000` 存在于锁定的 7.4–8.4.22 pre-9.0 正式源码、9.0.23 至 18.6 的全部正式快照及 19 Beta 3 预览快照。同 tag 的 `REL8_1_4` `errcodes.sgml` 表已经列出 `XX000` 和条件名 `internal_error`，因此至少可以确认 8.1.4 已有该条件名。9.0 头文件视图中的类标题为 `Internal Error (PostgreSQL-specific error class)`，到 9.1 的文本定义变为 `Internal Error`。7.0–7.3 仍有候选源码缺口；这些是目录观察边界，不是确切实现引入日期的断言。

18.6 固定源码 commit 为 `724edf9bde9d356724ad384a2e196edc3c9f80f7`。默认严重级别到代码的映射以及上面的源码路径均有 18.6 证据。代表性运行案例没有接受确定且安全的 SQL 触发方式，因此两个目标的运行时状态均保持 `not_applicable`。

## 相关 {#related}

[`XX001` — `data_corrupted`](../xx001/) 和 [`XX002` — `index_corrupted`](../xx002/) 是更具体的损坏条件。[`P0001` — `raise_exception`](../p0001/) 是没有代码的 PL/pgSQL `RAISE EXCEPTION` 的通常默认值。[`57P01` — `admin_shutdown`](../57p01/) 是不同类别的服务器连接事件。[`25P02` — `in_failed_sql_transaction`](../25p02/) 是前一个错误导致的后续事务状态，不是 `XX000` 的同义词。

## 来源 {#sources}

结构化证据记录在[公开证据 JSON](../../data/evidence/xx000.json)中。源码记录固定到 PostgreSQL commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`；运行时记录保留精确的源码边界案例 ID 和两个目标摘要。

- `src.errcodes.18.6` — [`errcodes.txt`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L496-L502)
- `src.elog.18.6` — [`elog.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/error/elog.c#L442-L454)
- `src.nbtinsert.18.6`、`src.dsm.18.6`、`src.guc.18.6`、`src.uuid.18.6` 与 `src.bufmask.18.6` — 源码确认的内部路径
- `src.oat-hooks.18.6` — 在 `NOTICE` 中显式提供内部代码
- `doc.protocol.18` — [Error and Notice Message Fields](https://www.postgresql.org/docs/18/protocol-error-fields.html)
