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

  1. Retype the configured CSP value ensuring only ASCII characters are used.
  2. Replace Unicode punctuation with ASCII equivalents: curly quotes to ', en-dash to -, non-breaking space to space.
  3. 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

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


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)