apache/druid · error · IllegalArgumentException
Content-Security-Policy header value must be fully ASCII
Error message
Content-Security-Policy header value must be fully ASCII
What it means
Druid lets operators override the Content-Security-Policy response header via configuration. HTTP header values must be plain ASCII (or RFC 2047 encoded, which Druid does not implement), so asContentSecurityPolicyHeaderValue scans each character of the configured value and throws this IllegalArgumentException if any non-ASCII character is found.
Solutions
- Retype the configured CSP value ensuring only ASCII characters are used.
- Replace Unicode punctuation with ASCII equivalents: curly quotes to ', en-dash to -, non-breaking space to space.
- Validate the property file encoding and strip any BOM from config files.
Example fix
// before (config) drui...csp=default-src 'self'; frame-ancestors 'none'–style-src 'self' // after csp=default-src 'self'; frame-ancestors 'none'; style-src 'self'
Defensive patterns
Strategy: validation
Validate before calling
function isAscii(s) {
return /^\x00-\x7F]*$/.test(s);
}
if (!isAscii(config.contentSecurityPolicy)) {
throw new Error('Content-Security-Policy value must be fully ASCII');
} Type guard
function isAsciiHeader(value) {
return typeof value === 'string' && [...value].every(c => c.charCodeAt(0) <= 0x7F);
} Try / catch
try {
injector.getInstance(Lifecycle.class).start();
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("must be fully ASCII")) {
log.fatal("Fix configured CSP header value: %s", e.getMessage());
} else { throw e; }
} Prevention
- Type CSP config values in a plain-text editor, never paste from word processors or rich web pages.
- Check config files for BOM/non-ASCII bytes (e.g. `grep -P '[^\x00-\x7F]'`) before deploy.
- Use ASCII quote characters (' or ") and hyphens (-) in header config values.
When it happens
Trigger: Configuring druid.auth... response-header Content-Security-Policy (or the filter's configured value) with non-ASCII characters, e.g. a copy-pasted directive containing a Unicode quote, en-dash, or curly apostrophe.
Common situations: Pasting CSP strings from word processors or web pages that replace ASCII characters with typographic Unicode equivalents; accidentally including a BOM or non-breaking space.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- At least one task runner must be enabled
- Cannot define both uri and fileRegex
- Cannot have fault tolerance without durable storage
- Cannot mix sortable and unsortable key columns
- Cannot specify both versionRegex and fileRegex…
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/43b66d391a8eded0.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/server/initialization/jetty/StandardResponseHeaderFilterHolder.java:93
{
for (final String headerName : StandardResponseHeaderFilterHolder.STANDARD_HEADERS) {
if (serverResponse.getHeaders().contains(headerName) && proxyResponse.containsHeader(headerName)) {
// In EE8 compatible Jetty 12 using servlet API 4.x, setting a header to null is the accepted way to remove it.
proxyResponse.setHeader(headerName, null);
}
}
}
static String asContentSecurityPolicyHeaderValue(@Nullable final String contentSecurityPolicy)
{
if (contentSecurityPolicy == null || contentSecurityPolicy.trim().isEmpty()) {
return DEFAULT_CONTENT_SECURITY_POLICY;
} else {
// Header values must be ASCII or RFC 2047 encoded. We don't have an RFC 2047 encoder handy, so require
// that the value be plain ASCII.
for (int i = 0; i < contentSecurityPolicy.length(); i++) {
if (!CharUtils.isAscii(contentSecurityPolicy.charAt(i))) {
throw new IAE("Content-Security-Policy header value must be fully ASCII");
}
}
return contentSecurityPolicy;
}
}
@Override
public Filter getFilter()
{
return new StandardResponseHeaderFilter(contentSecurityPolicy);
}
@Override
public Class<? extends Filter> getFilterClass()
{
return StandardResponseHeaderFilter.class;
}View on GitHub (pinned to 9b90983fd2)