apache/shardingsphere · error · PostgreSQLProtocolException
Close type must be 'S' or 'P'. Got '%c'.
Error message
Close type must be 'S' or 'P'. Got '%c'.
What it means
PostgreSQLComClosePacket.Type.valueOf(char) maps the single byte after the Close message tag to either 'S' (prepared statement) or 'P' (portal). Any other byte throws PostgreSQLProtocolException 'Close type must be 'S' or 'P'. Got '%c'.', meaning the incoming Close message is malformed per the PostgreSQL frontend/backend protocol.
Source
Thrown at database/protocol/dialect/postgresql/src/main/java/org/apache/shardingsphere/database/protocol/postgresql/packet/command/query/extended/close/PostgreSQLComClosePacket.java:75
PORTAL('P');
private final char value;
/**
* Value of type.
*
* @param type type char
* @return type
* @throws PostgreSQLProtocolException PostgreSQL protocol exception
*/
public static Type valueOf(final char type) {
for (Type each : values()) {
if (type == each.value) {
return each;
}
}
throw new PostgreSQLProtocolException("Close type must be 'S' or 'P'. Got '%c'.", type);
}
}
}
View on GitHub (pinned to e952770a21)
Solutions
- Capture the raw bytes of the Close message and verify the client implementation sends exactly 'S' or 'P' after the tag
- If using a custom client, check message construction order against the PostgreSQL protocol spec (Close is: tag, type byte, name, NUL)
- Rule out middleboxes/proxies that rewrite the stream; test the client directly against the proxy
- Report a driver bug if a mainstream driver emits the invalid byte
Defensive patterns
Strategy: validation
Validate before calling
if (typeChar != 'S' && typeChar != 'P') { throw new IllegalArgumentException("Close type byte must be 'S' or 'P'"); } Try / catch
catch (PostgreSQLProtocolException e) { /* terminate connection: stream is untrusted/desynced */ } Prevention
- Test custom wire clients against vanilla PostgreSQL first
- Verify Close message byte order per protocol spec
- Watch for middleware that rewrites the byte stream
When it happens
Trigger: A client sends a Close message (tag 'C') whose type byte is neither 'S' nor 'P' — from a buggy driver, a protocol-level proxy mangling bytes, a truncated TCP stream, or fuzzed input.
Common situations: Custom wire-protocol clients, broken middleware between client and proxy, partial writes producing byte misalignment, or driver/protocol version mismatches.
Related errors
- Connection [%s] is not registered.
- BLR is too short: %s
- Unsupported PostgreSQL format code `%s`
- Can not find `%s` in PostgreSQL command packet type.
- Can not find value `%s` in PostgreSQL column type.
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/5d6d8f4193ad0b95.
Report an issue: GitHub.