{"record":{"id":"fe6575548ef914d9","repo":"alibaba/nacos","slug":"agent-extensions-contains-a-non-string-json-object","errorCode":null,"errorMessage":"Agent extensions contains a non-string JSON object key","messagePattern":"Agent extensions contains a non-string JSON object key","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/com/alibaba/nacos/ai/service/agent/metadata/AgentResourceExtSerializer.java","lineNumber":152,"sourceCode":"        if (provider == null) {\n            return;\n        }\n        validateRequiredCodePointLength(provider.getName(), MAX_PROVIDER_NAME_LENGTH,\n            \"provider.name\");\n        validateOptionalAbsoluteUri(provider.getUrl(), \"provider.url\");\n    }\n    \n    private static void validateExtensions(Map<String, Object> extensions) {\n        if (extensions == null) {\n            return;\n        }\n        if (extensions.size() > MAX_EXTENSIONS) {\n            throw new IllegalArgumentException(\n                \"extensions exceeds \" + MAX_EXTENSIONS + \" entries\");\n        }\n        for (Map.Entry<?, ?> entry : extensions.entrySet()) {\n            if (!(entry.getKey() instanceof String)) {\n                throw new IllegalArgumentException(\n                    \"Agent extensions contains a non-string JSON object key\");\n            }\n            String key = (String) entry.getKey();\n            validateRequiredCodePointLength(key, MAX_EXTENSION_KEY_LENGTH, \"extension key\");\n            validateJsonValue(entry.getValue(), \"extension \" + entry.getKey());\n        }\n        final byte[] bytes;\n        try {\n            bytes = JacksonUtils.toJsonBytes(extensions);\n        } catch (NacosSerializationException e) {\n            throw new IllegalArgumentException(\"Unable to serialize Agent extensions\", e);\n        }\n        if (bytes.length > MAX_EXTENSIONS_SIZE) {\n            throw new IllegalArgumentException(\n                \"Agent extensions exceeds \" + MAX_EXTENSIONS_SIZE + \" bytes\");\n        }\n    }\n    ","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/ai/src/main/java/com/alibaba/nacos/ai/service/agent/metadata/AgentResourceExtSerializer.java#L134-L170","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nMap<Object,Object> ext = new HashMap<>();\next.put(404, \"not-found\"); // non-string key\n\n// after\nMap<String,Object> ext = new LinkedHashMap<>();\next.put(\"404\", \"not-found\");","handlingStrategy":"type-guard","validationCode":"for (Object k : extensions.keySet()) {\n    if (!(k instanceof String)) throw new IllegalArgumentException(\"non-string extension key: \" + k);\n}","typeGuard":"static boolean hasOnlyStringKeys(Map<String,?> map) {\n    for (Object k : map.keySet()) if (!(k instanceof String)) return false;\n    return true;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["ai-registry","agent","extensions","type-violation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}