apache/druid · warning
Failed to sanitize SearchResult in context key
Error message
Failed to sanitize SearchResult in context key [%s]
What it means
During OPA authorization, LDAP SearchResult objects found in the request context are sanitized to remove attributes not allowed to be forwarded. If sanitizeSearchResult throws a NamingException (LDAP/JNDI failure while reading attributes), the emitter logs this warning and substitutes an empty map for that context key so authorization can proceed.
Solutions
- Verify LDAP connectivity and keep-alive settings between the Druid process and the LDAP server; the sanitized value degrades to an empty map, so expect context attributes to be missing downstream.
- Inspect the warn-level NamingException stack trace to identify which attribute or referral failed and fix the LDAP schema/referral configuration.
- Increase connection pool timeouts (com.sun.jndi.ldap.connect.timeout / read timeout) so reads do not fail mid-sanitization.
- If the empty map breaks OPA policy decisions, update the OPA policy to tolerate a missing/empty context attribute instead of failing the request.
Example fix
// before
sanitizedContext.put(entry.getKey(), Collections.emptyMap());
// after
SearchResult sr = (SearchResult) entry.getValue();
if (sr.getAttributes() != null) {
sanitizedContext.put(entry.getKey(), sanitizeSearchResult(sr));
} else {
sanitizedContext.put(entry.getKey(), Collections.emptyMap());
} Defensive patterns
Strategy: fallback
Validate before calling
if (value instanceof SearchResult) {
SearchResult sr = (SearchResult) value;
if (sr.getAttributes() == null) {
log.warn("SearchResult for key %s has null attributes; will sanitize to empty map", key);
}
} Type guard
static boolean isSanitizableSearchResult(Object v) {
return v instanceof SearchResult && ((SearchResult) v).getAttributes() != null;
} Try / catch
try {
ctx.put(key, sanitizeSearchResult((SearchResult) value));
} catch (NamingException e) {
log.warn(e, "LDAP sanitize failed for key %s; using empty map", key);
ctx.put(key, Collections.emptyMap());
} Prevention
- Keep LDAP connection pools warm; set connect/read timeouts explicitly.
- Handle LDAP referrals deliberately (java.naming.referral=follow/throw) to avoid surprise NamingExceptions.
- Alert on this warning: a burst indicates LDAP connectivity degradation.
- Design OPA policies to tolerate missing/empty context attributes.
When it happens
Trigger: A context entry value is a javax.naming.directory.SearchResult and the underlying LDAP directory rejects the attribute read: closed or timed-out LDAP connection, referral chasing failure, schema violation reading a specific attribute, or a null/invalid SearchResult supplied by an LDAP extension into the auth context.
Common situations: Deployments using LDAP-based authentication feeding the OPA authorizer; misconfigured LDAP connection pools going stale, firewalls dropping idle LDAP connections, or LDAP servers returning partial results/referrals that JNDI cannot follow.
Related errors
- Access-Check-Result
- Access-Check-Result
- authResult.getErrorMessage()
- <authResult.getErrorMessage()>
- authResult.getErrorMessage()
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/88586825158f8975.
Report an issue: GitHub.
Appendix: source
Thrown at extensions-contrib/druid-opa-authorizer/src/main/java/org/apache/druid/security/opa/OpaAuthorizer.java:199
catch (Exception e) {
return Access.deny("An error occurred: " + e);
}
}
protected Map<String, Object> sanitizeContext(Map<String, Object> context)
{
if (context == null || context.isEmpty()) {
return context;
}
final Map<String, Object> sanitizedContext = new HashMap<>();
for (final Map.Entry<String, Object> entry : context.entrySet()) {
if (entry.getValue() instanceof SearchResult) {
try {
sanitizedContext.put(entry.getKey(), sanitizeSearchResult((SearchResult) entry.getValue()));
}
catch (NamingException e) {
LOG.warn(e, "Failed to sanitize SearchResult in context key [%s]", entry.getKey());
sanitizedContext.put(entry.getKey(), Collections.emptyMap());
}
} else {
// Keep other types as is, assuming they are serializable or handled by other means
sanitizedContext.put(entry.getKey(), entry.getValue());
}
}
return sanitizedContext;
}
private Map<String, Object> sanitizeSearchResult(SearchResult searchResult) throws NamingException
{
final Map<String, Object> sanitized = new HashMap<>();
sanitized.put("name", searchResult.getName());
try {
sanitized.put("nameInNamespace", searchResult.getNameInNamespace());
}View on GitHub (pinned to 9b90983fd2)