百科 / 错误代码 / Class 08 连接异常
08P01 protocol_violation
协议违规
ERROR 已实测 详解 实测通过
- 条件名
protocol_violation- 宏名称
ERRCODE_PROTOCOL_VIOLATION- 启用版本
- 7.4
- 状态
- 活跃
版本覆盖
速览
SQLSTATE 08P01 是 Class 08 中的 protocol_violation。08P01 表示前端/后端消息违反线路协议。选定原始 TCP 案例先完成启动并观察 ReadyForQuery(Z),再在合法帧中发送未知前端字节 Y,收到 C=08P01、S=FATAL、主报文 invalid frontend message type 89,并在客户端关闭 socket 前读到服务器 EOF。
含义
服务器协议解析器先接受启动交换,随后在派发 SQL 前拒绝未知的前端消息类型。选定路径为 FATAL invalid frontend message type 89,之后服务器发送 EOF;因此它是受影响 socket 的同步边界,不是 SQL 解析错误。
关键边界在于线路状态,而不是 SQL 文本。客户端可以已经到达 ReadyForQuery,却在下一条消息中发送错误类型,选定案例正是如此;启动帧损坏或代理改变帧边界也可能更早失败,并且可能没有可用会话。选定运行覆盖未知消息分派分支;下面的固定源码证据还覆盖不同的 Bind 和 message-buffer 解析分支,其他传输故障必须依据自身的 ErrorResponse 或日志判断。
08P01 并不意味着固定的严重级别或 socket 结果。在固定的 extended-query 路径中,Bind 消息的 parameter-format 数量或参数数量不匹配时报告 ERROR;顶层循环中止当前命令,等待协议规定的 Sync,然后才继续下一个 ReadyForQuery。固定的 message-buffer 读取器在缺少字节、字符串无效或报文尾部有数据时也使用 ERROR。这些可恢复的协议错误不同于未知消息类型:后者是 FATAL 边界,因为服务器不能再信任消息同步状态。
诊断
检查驱动或代理的协议版本、消息类型、帧长度、启动模式和连接所有权。选定证据中的 collector 是收集原始协议 ErrorResponse(C/S/M 及服务器 EOF)的对象,不是 csvlog/jsonlog。服务器关闭产生 FATAL 的 socket,案例不会复用它;独立的运行器连接能执行 SELECT 1 并保持 IDLE。这是线路协议边界,不是 SQL 语法,也不是客户端自行创建的 SQLSTATE。
按阶段解释恢复:
- 启动完成前没有会话级事务,驱动可能只有连接异常;如果服务器发过响应,应保留原始线路记录。
- 启动到达
Z后,未知前端消息会在已建立后端中被拒绝,但选定分支是FATAL,随后服务器关闭该 socket。即使客户端在协议失步前已经开始工作,也不能在这个 socket 上发送ROLLBACK。 - 经过连接池或代理时,要比较所有者实际发送的字节与服务器期望的协议版本和帧格式。另一条连接上的
SELECT 1只证明可达,不证明在途请求已经提交。
先根据主报文识别分支,再选择恢复动作。bind message has ... parameter formats 和 bind message supplies ... parameters 指向 extended-query 数量契约;no data left in message、insufficient data left in message、invalid string in message 和 invalid message format 指向报文主体或边界损坏。这些源码定义的 ERROR 变体在驱动仍能保持帧边界时可能通过 Sync 恢复;带 FATAL 的 invalid frontend message type ... 则表示选定 socket 已经失效。
处理
收到 FATAL 或服务器 EOF 时,关闭并丢弃受影响的 socket,修正协议或代理帧后重新连接。extended-query 的 ERROR 应让驱动发送协议有效的 Sync 并等待 ReadyForQuery,然后检查事务状态;Sync 不会回滚失败的显式事务,状态为 E 时仍须执行 ROLLBACK 或回到有意建立的保存点。若非幂等请求在途中,重放前先核对结果。独立探针只证明新连接可用。
将选定案例视为会话终止分支:读到服务器 EOF 后建立新连接,并且只重做已核对且具幂等性的操作。如果违规发生在会话建立前,应先修正启动或代理配置。只有客户端解析器异常或 socket 关闭而没有服务器 C 字段,不能把事件标成 08P01。
不要自行拼接字节,也不要把事务当作已经提交。若驱动无法保持报文边界或不实现 Sync 契约,应丢弃连接并核对请求结果。这一源码流程不改变选定未知字节运行:该案例的 FATAL socket 必须丢弃。
可复现案例
在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。
protocol_violation PG 10 / 18 有 SQL
前置条件
- A runner-owned disposable target is provisioned.
触发
Complete a startup handshake, then send a correctly framed unknown frontend message type.
断言
- The selected server diagnostic has the expected SQLSTATE
- The selected recovery/probe assertions pass
- Runner-owned resources are cleaned up
处置
Follow the case-specific repair statements and verify the resulting state.
清理
Drop the case schema with an owner connection.
报文
固定的协议解析路径以 FATAL 发出主报文 invalid frontend message type %d,其中字节数值是动态的。选定的 Y 字节记录为 89。SQLSTATE 的依据是原始 ErrorResponse,而不是客户端异常。
其他固定源码分支以 ERROR 发出以下主报文模板:
bind message has %d parameter formats but %d parametersbind message supplies %d parameters, but prepared statement "%s" requires %dno data left in messageinsufficient data left in messageinvalid string in messageinvalid message format
这些 Bind 和 message-buffer 变体在本页中是源码证据,不是新增运行观察,也不会全部终止 socket。
选定的线路顺序是:启动交换 → Z ReadyForQuery → 合法帧中的类型字节 Y(十进制 89)→ ErrorResponse C=08P01、S=FATAL、M=invalid frontend message type 89 → 服务器 EOF。collector 直接收集这些协议字段和 EOF,既不是 csvlog/jsonlog 记录,也不是后续独立探针。
报文模板
源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。
invalid frontend message type %d
来源:src/backend/tcop/postgres.c @ REL_18_6 · src/backend/tcop/postgres.c @ REL_10_23
bind message has %d parameter formats but %d parameters
bind message supplies %d parameters, but prepared statement "%s" requires %d
no data left in message
insufficient data left in message
invalid string in message
invalid message format
代表案例
SQL 探针用于检查独立连接。真实触发是运行器拥有的 TCP 握手后发送未知前端消息字节,不能只用 SQL 表达。
SELECT 1;
18.6 服务器记录为 C=08P01、S=FATAL、主报文 invalid frontend message type 89;启动到达 Z,服务器 EOF 断言为 True,独立探针返回 1,状态 IDLE。因此没有复用触发错误的连接。
可下载的案例与证据投影分别是 08P01 案例 JSON 和 作者证据。运行器清单为 verify/cases/08P01/cases.json;发布前会将页面 SQL 与共享注册表比对。
版本
上面的生成事实表记录锁定的目录快照和最早观察到的定义。本页自然运行范围是 PostgreSQL 18.6 与 10.21,不能据此推断所有中间版本的行为。
来源
- 上游源码 doc/src/sgml/protocol.sgml
- 上游源码 src/backend/utils/errcodes.txt
- 上游源码 src/backend/tcop/postgres.c 第 1483–1580 行
- 上游源码 src/backend/tcop/postgres.c 第 3863–3980 行
- 上游源码 src/backend/libpq/pqformat.c 第 432–682 行
- 上游源码 src/backend/tcop/postgres.c 第 430–432 行
- 上游源码 src/backend/tcop/postgres.c 第 454–456 行
- 核验材料 verify/cases/08P01/cases.json
- 核验材料 verify/cases/08P01/snippets.json
- 核验材料 raw/calls/REL_10_23.jsonl
- 核验材料 raw/calls/REL_18_6.jsonl
证据
断言
每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。
-
08P01 is the protocol_violation condition in Class 08.
-
The fixed source paths associated with 08P01 report the condition in the mechanism selected for this page.
-
The fixed extended-query Bind path reports ERROR 08P01 for parameter-format cardinality mismatches or a parameter count that differs from the prepared statement. After an ERROR while processing an extended-query message, the top-level loop skips messages until a protocol-valid Sync and then resumes the normal ReadyForQuery flow; this ERROR path is distinct from the unknown frontend type FATAL branch.
-
The fixed REL_10_23 pqformat readers report ERROR 08P01 for a depleted message, insufficient bytes, an invalid string, or trailing message data. These parser errors are source-only examples of protocol_violation and do not imply the unknown-message FATAL socket termination.
-
The selected protocol_violation case passed with the expected structured diagnostics, recovery assertions, and cleanup on PostgreSQL 18.6 and 10.21.
-
The selected unknown-message branch occurs after startup reaches ReadyForQuery, emits a FATAL ErrorResponse, and closes the affected socket; a pre-session protocol failure has no session transaction, and a client EOF without the server ErrorResponse is not sufficient to assign 08P01.
-
The locked catalogue records 08P01 in the listed snapshots; the runtime comparison here is limited to PostgreSQL 18.6 and 10.21.
运行记录
| 目标 | 服务器版本 | 结果 | 覆盖案例 |
|---|---|---|---|
| latest | 18.6 (Homebrew) | passed | protocol_violation |
| pg10 | 10.21 (Debian 10.21-1.pgdg90+1) | passed | protocol_violation |
同类错误代码
Class 08 连接异常 下的其他成员。