alibaba/nacos · error · IllegalArgumentException
AgentResourceExt must be a JSON object
Error message
AgentResourceExt must be a JSON object
What it means
validateJsonShape() parses the raw JSON to a Map; if the result is null (which only happens when the JSON literal is the token 'null'), it throws 'AgentResourceExt must be a JSON object'. The ext must be a JSON object, and a JSON null is explicitly not allowed even though it is valid JSON.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/metadata/AgentResourceExtSerializer.java:306
private static void putIfPresent(Map<String, Object> target, String field, Object value) {
if (value != null) {
target.put(field, value);
}
}
private static void validateJsonShape(String json) {
if (json == null || json.isEmpty()) {
throw new IllegalArgumentException("AgentResourceExt JSON must not be empty");
}
validateSingleJsonValue(json);
final Map<?, ?> root;
try {
root = JacksonUtils.toObj(json, Map.class);
} catch (NacosDeserializationException e) {
throw new IllegalArgumentException("Invalid AgentResourceExt", e);
}
if (root == null) {
throw new IllegalArgumentException("AgentResourceExt must be a JSON object");
}
rejectUnknownFields(root, ROOT_FIELDS, "AgentResourceExt");
validateJsonInteger(root, "schemaVersion");
validateOptionalJsonText(root, "displayName");
validateOptionalJsonText(root, "iconUrl");
validateProviderShape(root);
validateExtensionsShape(root);
validateCatalogShape(root);
}
private static void validateProviderShape(Map<?, ?> root) {
if (!root.containsKey("provider")) {
return;
}
Map<?, ?> provider = requireJsonObject(root.get("provider"), "provider");
rejectUnknownFields(provider, PROVIDER_FIELDS, "AgentProvider");
validateRequiredJsonText(provider, "name");
validateOptionalJsonText(provider, "url");View on GitHub (pinned to 9b989acdf1)
Solutions
- Ensure the ext JSON is an object, not the literal null; re-publish the agent with a proper object payload.
- At the write site, never persist String.valueOf(null) or a serializer that emits 'null'; skip the column or write {}-equivalent.
- Guard deserialize callers to treat literal "null" as 'no extension'.
Example fix
// before: stored ext is the literal string "null" // after AgentResourceExt ext = new AgentResourceExt(); ext.setSchemaVersion(AgentResourceExt.SCHEMA_VERSION); ext.setVersionCatalog(catalog); row.setExt(AgentResourceExtSerializer.serialize(ext));
Defensive patterns
Strategy: validation
Validate before calling
static AgentResourceExt safeDeserialize(String raw) {
if (raw == null || raw.isEmpty() || "null".equals(raw.trim())) {
return null; // treat JSON null / empty as 'no extension'
}
return AgentResourceExtSerializer.deserialize(raw);
} Type guard
static boolean isJsonObjectLiteral(String raw) {
String t = raw == null ? "" : raw.trim();
return !t.isEmpty() && !"null".equals(t) && t.startsWith("{");
} Prevention
- Never persist the literal 'null' string into ai_resource.ext.
- At write sites, skip the column or write a real object when there is no extension.
- Treat literal 'null' as 'no extension' at read sites.
When it happens
Trigger: deserialize("null") or a stored ai_resource.ext whose value is the literal string "null". The empty case is caught earlier; this is specifically the JSON null token.
Common situations: A previous write stored the Java string 'null' (e.g. String.valueOf(nullObject) or a serializer that emitted null), or a test/fixture using "null".
Related errors
- Invalid persisted Agent tags
- Persisted Agent tags must be a JSON array
- Persisted Agent tags must contain only strings
- Stored Agent versionInfo must not be null
- Invalid AgentResourceExt
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/8e321ea116613a6c.
Report an issue: GitHub.