apache/incubator-seata · error · FrameworkException
Invalid Client ID: {clientId}
Error message
Invalid Client ID: {clientId} What it means
FrameworkException thrown by ChannelManager.getChannel when the clientId string does not parse into exactly 3 colon-separated parts. Seata encodes a client identity as ApplicationId:IP:Port; anything else (missing segments, wrong separators, extra colons in IPv6 without brackets, null) is rejected before any channel lookup.
Source
Thrown at core/src/main/java/org/apache/seata/core/rpc/netty/ChannelManager.java:369
}
return null;
}
/**
* Gets get channel.
*
* @param resourceId Resource ID
* @param clientId Client ID - ApplicationId:IP:Port
* @param tryOtherApp try other app
* @return Corresponding channel, NULL if not found.
*/
public static Channel getChannel(String resourceId, String clientId, boolean tryOtherApp) {
Channel resultChannel = null;
String[] clientIdInfo = readClientId(clientId);
if (clientIdInfo == null || clientIdInfo.length != 3) {
throw new FrameworkException("Invalid Client ID: " + clientId);
}
if (StringUtils.isBlank(resourceId)) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("No channel is available, resourceId is null or empty");
}
return null;
}
String targetApplicationId = clientIdInfo[0];
String targetIP = clientIdInfo[1];
int targetPort = Integer.parseInt(clientIdInfo[2]);
ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<Integer, RpcContext>>> applicationIdMap =
RM_CHANNELS.get(resourceId);
if (targetApplicationId == null || applicationIdMap == null || applicationIdMap.isEmpty()) {
if (LOGGER.isInfoEnabled()) {View on GitHub (pinned to e01f97c6db)
Solutions
- Pass the clientId exactly as delivered in the RegisterRMRequest (applicationId:ip:port), never reconstruct it
- For IPv6, use the bracketed form or verify how the client encoded the address
- Log the raw clientId at the boundary and validate it with a 3-part split before calling channel APIs
- Upgrade client and server to matching seata versions so id formats agree
Example fix
// before
String clientId = app + ':' + host + ':' + port + ':extra'; // malformed
server.sendSyncRequest(resourceId, clientId, msg, true);
// after
String clientId = app + ':' + host + ':' + port; // ApplicationId:IP:Port
if (clientId.split(":").length != 3) {
throw new IllegalArgumentException("bad clientId: " + clientId);
}
server.sendSyncRequest(resourceId, clientId, msg, true); Defensive patterns
Strategy: validation
Validate before calling
static boolean isValidClientId(String clientId) {
if (clientId == null) return false;
String[] parts = clientId.split(":");
return parts.length == 3 && !parts[0].isEmpty() && !parts[1].isEmpty()
&& parts[2].matches("\\d+");
} Type guard
static boolean isValidClientId(String clientId) {
return clientId != null && clientId.split(":").length == 3;
} Try / catch
catch (FrameworkException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Invalid Client ID")) {
// reject the request with a 4xx-style error; log the raw id
}
} Prevention
- Only forward clientIds received from RegisterRMRequest verbatim
- Validate id shape at API boundaries (3 colon-separated parts)
- Use bracketed IPv6 literals to survive naive splitting
When it happens
Trigger: Calling any server API that resolves an RM channel by clientId (e.g. sendSyncRequest(resourceId, clientId, ...)) with a malformed clientId — readClientId returns null or an array whose length != 3.
Common situations: Custom code constructing clientIds by hand; IPv6 addresses containing colons that break naive splitting; clientId truncated or re-encoded through a config/serialization layer; version drift where an old client sends a legacy id format.
Related errors
- listen port: %s is invalid!
- Two or more start states, ${target} and ${definitions.StartS
- URL must not be null or blank
- ip and port string cannot be empty!
- "pageNum range not in [" + MIN_PAGE_NUM + "-" + MAX_PAGE_NUM
AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14).
Data as JSON: /api/errors/3d1274ac309adf2a.
Report an issue: GitHub.