alibaba/nacos · error · IllegalArgumentException

list size must be a multiple of 2

Error message

list size must be a multiple of 2

What it means

Thrown by Header.addAll(List<String>) when the supplied KV list has an odd number of entries. The method treats the list as flat key/value pairs (odd index = key, even index = value), so an odd size leaves a dangling key with no value and the contract is violated. It is an IllegalArgumentException raised before any entry is put into the header map.

Source

Thrown at common/src/main/java/com/alibaba/nacos/common/http/param/Header.java:113

        List<String> list = new ArrayList<>(header.size() * 2);
        Iterator<Map.Entry<String, String>> iterator = iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            list.add(entry.getKey());
            list.add(entry.getValue());
        }
        return list;
    }
    
    /**
     * Add all KV list to header. The odd index is key and the even index is value.
     *
     * @param list KV list
     * @return header
     */
    public Header addAll(List<String> list) {
        if ((list.size() & 1) != 0) {
            throw new IllegalArgumentException("list size must be a multiple of 2");
        }
        for (int i = 0; i < list.size();) {
            String key = list.get(i++);
            if (StringUtils.isNotEmpty(key)) {
                header.put(key, list.get(i++));
            }
        }
        return this;
    }
    
    /**
     * Add all parameters to header.
     *
     * @param params parameters
     */
    public void addAll(Map<String, String> params) {
        if (MapUtil.isNotEmpty(params)) {
            for (Map.Entry<String, String> entry : params.entrySet()) {

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Ensure the list length is even before calling addAll: assert (list.size() & 1) == 0, or guard with an if.
  2. Build the list from an explicit Map.entrySet() loop that always writes both key and value, so a pair can never be split.
  3. Prefer header.addAll(Map<String,String>) (the map overload in the same class) over the flat List form to make pairing structural.
  4. If the list is user supplied, log list.size() and the offending tail before rejecting so the caller sees the unpaired key.

Example fix

// before
List<String> flat = new ArrayList<>();
headers.forEach((k,v) -> { flat.add(k); /* v conditionally skipped */ });
header.addAll(flat); // throws if any value omitted

// after
Map<String,String> safe = new LinkedHashMap<>();
headers.forEach((k,v) -> { if (k != null && v != null) safe.put(k, v); });
header.addAll(safe);
Defensive patterns

Strategy: validation

Validate before calling

if (list == null || (list.size() & 1) != 0) {
    throw new IllegalArgumentException("header KV list must have even size, got " + (list == null ? 0 : list.size()));
}
header.addAll(list);

Type guard

boolean isEvenKvList(List<String> list) {
    return list != null && (list.size() & 1) == 0;
}

Prevention

When it happens

Trigger: Calling Header.newInstance().addAll(list) or header.addAll(Arrays.asList("k1","v1","k2")) where list.size() is odd; building a Header from a flattened collection produced by splitting or streaming without ensuring pairs.

Common situations: Manually flattening a Map into an alternating key/value List and dropping the last value; passing a varargs/collection whose last element was filtered out; off-by-one when zipping headers from an HTTP response into a flat list.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/0f397f364e0a02a2. Report an issue: GitHub.