alibaba/nacos · error · IllegalArgumentException
Agent extensions contains a non-string JSON object key
Error message
Agent extensions contains a non-string JSON object key
What it means
validateExtensions() iterates extensions.entrySet() and requires every key to be a String instance. Because the model field is Map<String,Object>, a non-String key can only arise when the map is built programmatically with a non-String key (JSON itself cannot carry non-string object keys). This guard rejects maps that would not round-trip to JSON.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/metadata/AgentResourceExtSerializer.java:152
if (provider == null) {
return;
}
validateRequiredCodePointLength(provider.getName(), MAX_PROVIDER_NAME_LENGTH,
"provider.name");
validateOptionalAbsoluteUri(provider.getUrl(), "provider.url");
}
private static void validateExtensions(Map<String, Object> extensions) {
if (extensions == null) {
return;
}
if (extensions.size() > MAX_EXTENSIONS) {
throw new IllegalArgumentException(
"extensions exceeds " + MAX_EXTENSIONS + " entries");
}
for (Map.Entry<?, ?> entry : extensions.entrySet()) {
if (!(entry.getKey() instanceof String)) {
throw new IllegalArgumentException(
"Agent extensions contains a non-string JSON object key");
}
String key = (String) entry.getKey();
validateRequiredCodePointLength(key, MAX_EXTENSION_KEY_LENGTH, "extension key");
validateJsonValue(entry.getValue(), "extension " + entry.getKey());
}
final byte[] bytes;
try {
bytes = JacksonUtils.toJsonBytes(extensions);
} catch (NacosSerializationException e) {
throw new IllegalArgumentException("Unable to serialize Agent extensions", e);
}
if (bytes.length > MAX_EXTENSIONS_SIZE) {
throw new IllegalArgumentException(
"Agent extensions exceeds " + MAX_EXTENSIONS_SIZE + " bytes");
}
}
View on GitHub (pinned to 9b989acdf1)
Solutions
- Always use Map<String,Object> with String keys when building extensions.
- If keys originate as numbers/enums, convert with String.valueOf(key) before insertion.
- Run a unit test that serializes a freshly built ext to catch non-string keys before deploy.
Example fix
// before
Map<Object,Object> ext = new HashMap<>();
ext.put(404, "not-found"); // non-string key
// after
Map<String,Object> ext = new LinkedHashMap<>();
ext.put("404", "not-found"); Defensive patterns
Strategy: type-guard
Validate before calling
for (Object k : extensions.keySet()) {
if (!(k instanceof String)) throw new IllegalArgumentException("non-string extension key: " + k);
} Type guard
static boolean hasOnlyStringKeys(Map<String,?> map) {
for (Object k : map.keySet()) if (!(k instanceof String)) return false;
return true;
} Prevention
- Always type extension maps as Map<String,Object>.
- Convert numeric/enum keys with String.valueOf before insertion.
- Run a serializer round-trip in unit tests to catch non-string keys.
When it happens
Trigger: Server-side code or a plugin constructs the extensions Map with an Integer/Long/enum key and then calls serialize(). Cannot occur from JSON deserialization because Jackson coerces object keys to String.
Common situations: A migration/import script using Map<Integer,Object>, an enum used as a map key, or Guava/maps built from a stream of non-string keys.
Related errors
- {} contains a non-string JSON object key
- {} is not a JSON value
- extensions exceeds 32 entries
- Unable to serialize Agent extensions
- Agent extensions exceeds {} bytes
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/fe6575548ef914d9.
Report an issue: GitHub.