apache/incubator-seata · error · ParseEndpointException
Metadata 'external' is not a List.
Error message
Metadata 'external' is not a List.
What it means
Node.updateMetadataWithExternalEndpoints expects metadata['external'] to be either absent or a List. If the key exists but holds another type (String, Map, scalar), it throws ParseEndpointException 'Metadata 'external' is not a List.' because it needs to append ExternalEndpoint objects to the existing list.
Source
Thrown at common/src/main/java/org/apache/seata/common/metadata/Node.java:242
}
public Map<String, Object> updateMetadataWithExternalEndpoints(
Map<String, Object> metadata, List<Node.ExternalEndpoint> externalEndpoints) {
Object obj = metadata.get("external");
if (obj == null) {
if (!externalEndpoints.isEmpty()) {
Map<String, Object> metadataMap = new HashMap<>(metadata);
metadataMap.put("external", externalEndpoints);
return metadataMap;
}
return metadata;
}
if (obj instanceof List) {
List<Node.ExternalEndpoint> oldList = (List<Node.ExternalEndpoint>) obj;
oldList.addAll(externalEndpoints);
return metadata;
} else {
throw new ParseEndpointException("Metadata 'external' is not a List.");
}
}
public static class ExternalEndpoint {
private String host;
private int controlPort;
private int transactionPort;
public ExternalEndpoint(String host, int controlPort, int transactionPort) {
this.host = host;
this.controlPort = controlPort;
this.transactionPort = transactionPort;
}
public String getHost() {
return host;
}View on GitHub (pinned to e01f97c6db)
Solutions
- Find who wrote the non-List value into metadata['external'] and have it write a List<Node.ExternalEndpoint> (or omit the key).
- If metadata came from JSON deserialization, ensure 'external' decodes as an array, not an object/string.
- Upgrade both seata server and client to versions agreeing on the 'external' metadata shape.
Example fix
// before
metadata.put("external", "10.0.0.1:7091:8091"); // String -> throws on update
// after
metadata.put("external", new ArrayList<Node.ExternalEndpoint>(
List.of(new Node.ExternalEndpoint("10.0.0.1", 7091, 8091)))); Defensive patterns
Strategy: type-guard
Validate before calling
Map<String, Object> safe = new HashMap<>(metadata);
Object ext = safe.get("external");
if (ext != null && !(ext instanceof List)) {
safe.remove("external"); // or convert: safe.put("external", parseToList(ext));
}
node.updateMetadataWithExternalEndpoints(safe, externalEndpoints); Type guard
boolean hasListExternal(Map<String, Object> metadata) {
Object ext = metadata == null ? null : metadata.get("external");
return ext == null || ext instanceof List;
} Try / catch
try {
node.updateMetadataWithExternalEndpoints(metadata, externalEndpoints);
} catch (ParseEndpointException e) {
if (e.getMessage().contains("not a List")) {
// metadata['external'] corrupted by another writer: reset the key to a fresh List and retry
}
throw e;
} Prevention
- Only ever write List<Node.ExternalEndpoint> into the 'external' metadata key.
- When deserializing cluster metadata from JSON, assert 'external' decodes as an array.
- Keep seata server and client versions aligned so metadata shapes agree.
When it happens
Trigger: Calling updateMetadataWithExternalEndpoints with a metadata map where 'external' was previously populated as a non-List value — typically another component serialized it to a JSON string, or a custom metadata provider set it to a Map/object.
Common situations: Mixing seata versions where 'external' metadata shape changed; custom metadata providers or interceptors writing a string into the 'external' key; deserializing metadata from JSON into Map<String,Object> that yields a String instead of List.
Related errors
- ERR_CONFIG
- No JsonCodec provider found. Please add json-common-core to
- not found service provider for : {} caused by {}
- not found service provider for : {}
- Extension instance(definition: {}, class: {}) could not be
AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14).
Data as JSON: /api/errors/ee657f2b1c3218a8.
Report an issue: GitHub.