{"record":{"id":"bd4b326a9ccc20d6","repo":"apache/druid","slug":"couldn-t-serialize-authorizer-groupmappingmap","errorCode":null,"errorMessage":"Couldn't serialize authorizer groupMappingMap!","messagePattern":"Couldn't serialize authorizer groupMappingMap!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicAuthUtils.java","lineNumber":207,"sourceCode":"      groupMappingMap = new HashMap<>();\n    } else {\n      try {\n        groupMappingMap = objectMapper.readValue(groupMappingMapBytes, BasicAuthUtils.AUTHORIZER_GROUP_MAPPING_MAP_TYPE_REFERENCE);\n      }\n      catch (IOException ioe) {\n        throw new RuntimeException(\"Couldn't deserialize authorizer groupMappingMap!\", ioe);\n      }\n    }\n    return groupMappingMap;\n  }\n\n  public static byte[] serializeAuthorizerGroupMappingMap(ObjectMapper objectMapper, Map<String, BasicAuthorizerGroupMapping> groupMappingMap)\n  {\n    try {\n      return objectMapper.writeValueAsBytes(groupMappingMap);\n    }\n    catch (IOException ioe) {\n      throw new ISE(ioe, \"Couldn't serialize authorizer groupMappingMap!\");\n    }\n  }\n\n  public static Map<String, BasicAuthorizerRole> deserializeAuthorizerRoleMap(\n      ObjectMapper objectMapper,\n      byte[] roleMapBytes\n  )\n  {\n    Map<String, BasicAuthorizerRole> roleMap;\n    if (roleMapBytes == null) {\n      roleMap = new HashMap<>();\n    } else {\n      try {\n        roleMap = objectMapper.readValue(roleMapBytes, BasicAuthUtils.AUTHORIZER_ROLE_MAP_TYPE_REFERENCE);\n      }\n      catch (IOException ioe) {\n        throw new RuntimeException(\"Couldn't deserialize authorizer roleMap!\", ioe);\n      }","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicAuthUtils.java#L189-L225","documentation":"Thrown by BasicAuthUtils.serializeAuthorizerGroupMappingMap when Jackson's ObjectMapper fails to write the authorizer group-mapping map to a byte array. Druid serializes group mappings before persisting them in metadata storage or broadcasting cache updates; an IOException during that write is wrapped in this IllegalStateException. It almost always indicates a serialization configuration or object-graph problem, not user input.","triggerScenarios":"Calling serializeAuthorizerGroupMappingMap with a groupMappingMap whose BasicAuthorizerGroupMapping objects fail Jackson serialization (e.g. self-referencing structures, an ObjectMapper misconfigured for the type, or an underlying JsonSerializer throwing IOException).","commonSituations":"Custom BasicAuthorizerGroupMapping implementations lacking proper Jackson annotations; corrupted in-memory state after a partial config update; using a raw ObjectMapper without Druid modules registered.","solutions":["Inspect the wrapped IOException cause chain to find which field or type failed serialization","Ensure the ObjectMapper passed in is the fully-initialized Druid mapper (with all Jackson modules registered)","Check any custom BasicAuthorizerGroupMapping implementations for non-serializable fields or missing @JsonSerialize/@JsonProperty annotations","If transient, re-trigger the config update; if persistent, fix the offending object graph"],"exampleFix":"// before\nbyte[] bytes = BasicAuthUtils.serializeAuthorizerGroupMappingMap(new ObjectMapper(), groupMappingMap);\n// after\nbyte[] bytes = BasicAuthUtils.serializeAuthorizerGroupMappingMap(jsonMapper, groupMappingMap); // jsonMapper = fully configured Druid ObjectMapper","handlingStrategy":"try-catch","validationCode":"if (groupMappingMap == null || groupMappingMap.isEmpty()) { throw new IllegalArgumentException(\"groupMappingMap empty\"); }\ngroupMappingMap.values().forEach(vm -> { if (vm.getClass().getPackage().getName().startsWith(\"org.apache.druid.security.basic\") && !vm.getClass().getName().equals(\"org.apache.druid.security.basic.BasicAuthorizerGroupMapping\")) { throw new IllegalArgumentException(\"custom mapping class may not be Jackson-serializable: \" + vm.getClass()); } });","typeGuard":"boolean isSerializable(ObjectMapper m, Object o) { try { m.canSerialize(o.getClass()); return true; } catch (Exception e) { return false; } }","tryCatchPattern":"try { byte[] b = BasicAuthUtils.serializeAuthorizerGroupMappingMap(jsonMapper, groupMappingMap); } catch (ISE e) { LOG.error(e, \"group-mapping serialization failed; check custom mapping classes and mapper config\"); throw e; }","preventionTips":["Always pass the Druid-injected jsonMapper, never a bare new ObjectMapper()","Keep BasicAuthorizerGroupMapping implementations free of cyclic or non-serializable fields","Add unit tests that round-trip (serialize→deserialize) every custom group-mapping type","Keep Jackson modules consistent across all nodes in the cluster"],"tags":["jackson","serialization","basic-security"],"backgroundTag":"json-marshal-failed","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}