eclipse-vertx/vert.x · error · IllegalArgumentException
a header value contains a prohibited character '127': <seq>
Error message
a header value contains a prohibited character '127': <seq>
What it means
Inside validateValueChar, the per-character state machine for header values rejects DEL (0x7F) outright with IllegalArgumentException. This is the fine-grained path reached after a non-printable char triggers deeper validation; it guarantees no prohibited character ends up on the wire.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java:732
// we already expect the very-first character to be non-printable
int state = validateValueChar(seq, NO_CR_LF_STATE, seq.charAt(index));
for (int i = index + 1; i < seq.length(); i++) {
state = validateValueChar(seq, state, seq.charAt(i));
}
if (state != NO_CR_LF_STATE) {
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
}
}
private static int validateValueChar(CharSequence seq, int state, char ch) {
/*
* State:
* 0: Previous character was neither CR nor LF
* 1: The previous character was CR
* 2: The previous character was LF
*/
if (ch == 0x7F) {
throw new IllegalArgumentException("a header value contains a prohibited character '127': " + seq);
}
if ((ch & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
// this is a rare scenario
validateNonPrintableCtrlChar(seq, ch);
// this can include LF and CR as they are non-printable characters
if (state == NO_CR_LF_STATE) {
// Check the CRLF (HT | SP) pattern
switch (ch) {
case '\r':
return CR_STATE;
case '\n':
return LF_STATE;
}
return NO_CR_LF_STATE;
}
}
if (state != NO_CR_LF_STATE) {
// this is a rare scenarioView on GitHub (pinned to fb308bd8c3)
Solutions
- Reject or sanitize values containing 0x7F before calling headers.set/add
- Validate inputs at the boundary (decode/sanitize once) rather than at each header write
- Encode opaque/binary data (Base64) instead of passing raw chars
Example fix
// before
String v = new String(bytes, StandardCharsets.US_ASCII);
request.putHeader("X-Data", v);
// after
String v = Base64.getEncoder().encodeToString(bytes);
request.putHeader("X-Data", v); Defensive patterns
Strategy: validation
Validate before calling
boolean hasProhibitedChar(CharSequence v) {
for (int i = 0; i < v.length(); i++) {
char c = v.charAt(i);
if (c == 0x7F || (c < 0x20 && c != 0x09)) return true;
}
return false;
}
if (hasProhibitedChar(value)) value = sanitize(value); Try / catch
try {
request.putHeader(name, value);
} catch (IllegalArgumentException e) {
request.putHeader(name, value.replaceAll("[\\u0000-\\u001F\\u007F]", ""));
} Prevention
- Sanitize once at the input boundary rather than at every header write
- Use Base64 for opaque or binary header content
- Fuzz-test outgoing header construction with control characters
When it happens
Trigger: Setting an HTTP header value that contains U+007F, validated by the state machine in validateValueChar (often entered via validateSequenceHeaderValue after a control char is seen).
Common situations: Header values assembled from binary or escaped data where a literal DEL survives; fuzzed or adversarial input passed into outgoing headers.
Related errors
- a header value contains a prohibited character '127': <value
- a header value must not end with '\r' or '\n':<seq>
- only '\n' is allowed after '\r': <seq>
- only ' ' and '\t' are allowed after '\n': <seq>
- a header value contains a prohibited character '<charCode>':
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/fc2becc8936c6a38.
Report an issue: GitHub.