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

  1. Find who wrote the non-List value into metadata['external'] and have it write a List<Node.ExternalEndpoint> (or omit the key).
  2. If metadata came from JSON deserialization, ensure 'external' decodes as an array, not an object/string.
  3. 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

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


AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14). Data as JSON: /api/errors/ee657f2b1c3218a8. Report an issue: GitHub.