apache/druid · error · IllegalStateException

Couldn't serialize authorizer userMap!

Error message

Couldn't serialize authorizer userMap!

What it means

BasicAuthUtils.serializeAuthorizerUserMap serializes Map<String, BasicAuthorizerUser> to JSON bytes; a Jackson IOException becomes ISE('Couldn't serialize authorizer userMap!'). Indicates the supplied map (or its contents) can't be serialized by the given mapper.

Source

Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/BasicAuthUtils.java:178

      userMap = new HashMap<>();
    } else {
      try {
        userMap = objectMapper.readValue(userMapBytes, BasicAuthUtils.AUTHORIZER_USER_MAP_TYPE_REFERENCE);
      }
      catch (IOException ioe) {
        throw new RuntimeException("Couldn't deserialize authorizer userMap!", ioe);
      }
    }
    return userMap;
  }

  public static byte[] serializeAuthorizerUserMap(ObjectMapper objectMapper, Map<String, BasicAuthorizerUser> userMap)
  {
    try {
      return objectMapper.writeValueAsBytes(userMap);
    }
    catch (IOException ioe) {
      throw new ISE(ioe, "Couldn't serialize authorizer userMap!");
    }
  }

  public static Map<String, BasicAuthorizerGroupMapping> deserializeAuthorizerGroupMappingMap(
      ObjectMapper objectMapper,
      byte[] groupMappingMapBytes
  )
  {
    Map<String, BasicAuthorizerGroupMapping> groupMappingMap;
    if (groupMappingMapBytes == null) {
      groupMappingMap = new HashMap<>();
    } else {
      try {
        groupMappingMap = objectMapper.readValue(groupMappingMapBytes, BasicAuthUtils.AUTHORIZER_GROUP_MAPPING_MAP_TYPE_REFERENCE);
      }
      catch (IOException ioe) {
        throw new RuntimeException("Couldn't deserialize authorizer groupMappingMap!", ioe);
      }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Pass a properly typed Map<String, BasicAuthorizerUser> obtained from deserializeAuthorizerUserMap
  2. Use the standard Druid ObjectMapper configuration
  3. Add logging around serialization to capture the offending entry

Example fix

// before
Map<String, BasicAuthenticatorUser> m = ...;
BasicAuthUtils.serializeAuthorizerUserMap(mapper, (Map) m);
// after
Map<String, BasicAuthorizerUser> m = ...;
BasicAuthUtils.serializeAuthorizerUserMap(mapper, m);
Defensive patterns

Strategy: type-guard

Validate before calling

boolean valid = userMap.values().stream().allMatch(v -> v instanceof BasicAuthorizerUser);

Type guard

boolean isAuthorizerUserMap(Map<String, ?> m) {
  return m.values().stream().allMatch(BasicAuthorizerUser.class::isInstance);
}

Try / catch

try {
  byte[] b = BasicAuthUtils.serializeAuthorizerUserMap(mapper, userMap);
} catch (ISE e) {
  if (e.getMessage().contains("Couldn't serialize authorizer userMap!")) {
    // rebuild the map and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Persisting the authorizer user map when the wrong map type or a mapper-incompatible object is supplied.

Common situations: Custom extension code passing authenticator maps or foreign objects into the authorizer serializer; missing Jackson modules in a stripped-down ObjectMapper.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/893307303163e045. Report an issue: GitHub.