alibaba/nacos · error · IllegalArgumentException
{} must be an array
Error message
{} must be an array What it means
Inside each versionCatalog.onlineVersions entry, the 'labels' and 'protocols' fields must each be a JSON array. The validateStringArray helper (line 356) throws this when either field is present but is not an array (e.g. a string or number). The field name is interpolated into the message so you know which one failed.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/metadata/AgentResourceExtSerializer.java:357
validateOptionalJsonText(catalog, "latestVersion");
Object versionsValue = catalog.get("onlineVersions");
if (!(versionsValue instanceof List)) {
throw new IllegalArgumentException(
"AgentVersionCatalog onlineVersions must be an array");
}
for (Object entryValue : (List<?>) versionsValue) {
Map<?, ?> entry = requireJsonObject(entryValue, "versionCatalog entry");
rejectUnknownFields(entry, CATALOG_ENTRY_FIELDS, "AgentVersionCatalogEntry");
validateRequiredJsonText(entry, "version");
validateStringArray(entry, "labels");
validateStringArray(entry, "protocols");
}
}
private static void validateStringArray(Map<?, ?> object, String field) {
Object value = object.get(field);
if (!(value instanceof List)) {
throw new IllegalArgumentException(field + " must be an array");
}
for (Object item : (List<?>) value) {
if (!(item instanceof String)) {
throw new IllegalArgumentException(field + " must contain only strings");
}
}
}
private static Map<?, ?> requireJsonObject(Object value, String fieldName) {
if (!(value instanceof Map)) {
throw new IllegalArgumentException(fieldName + " must be a JSON object");
}
return (Map<?, ?>) value;
}
private static void validateRequiredJsonText(Map<?, ?> object, String field) {
if (!(object.get(field) instanceof String)) {
throw new IllegalArgumentException(field + " must be a string");View on GitHub (pinned to 9b989acdf1)
Solutions
- Wrap the value in square brackets: change "protocols":"a2a" to "protocols":["a2a"].
- If the field should be absent, omit it entirely rather than using a non-array placeholder.
- Ensure your DTO serializes List<String> fields as JSON arrays.
Example fix
// before
{"version":"1.0.0","labels":"stable","protocols":"a2a"}
// after
{"version":"1.0.0","labels":["stable"],"protocols":["a2a"]} Defensive patterns
Strategy: validation
Validate before calling
private static void ensureStringArray(Map<?,?> entry, String field) {
Object value = entry.get(field);
if (value != null && !(value instanceof List)) {
throw new IllegalArgumentException(field + " must be an array");
}
} Type guard
public static boolean isStringArrayField(Map<?,?> obj, String field) {
Object value = obj == null ? null : obj.get(field);
return value instanceof List;
} Try / catch
try {
AgentResourceExtSerializer.deserialize(json);
} catch (IllegalArgumentException e) {
if (e.getMessage().endsWith("must be an array")) {
// identify the field from the message and fix the JSON
}
throw e;
} Prevention
- Always use JSON arrays for labels and protocols, even for single values.
- Validate with a JSON Schema that enforces type: array for these fields.
- Test deserialization with representative payloads in CI.
When it happens
Trigger: Deserializing ai_resource.ext where a catalog entry's 'labels' or 'protocols' is a non-array JSON value. For example, "protocols":"a2a" instead of "protocols":["a2a"].
Common situations: Shorthand notation where a single protocol or label is written as a bare string; schema migration from a format that used comma-separated strings; incorrect client-side DTO mapping.
Related errors
- Missing AgentResourceExt field: versionCatalog
- AgentVersionCatalog onlineVersions must be an array
- {} must contain only strings
- {} must be a JSON object
- {} must be a string
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/c48c5d2c2dd645a7.
Report an issue: GitHub.