eclipse-vertx/vert.x · error · IllegalArgumentException

only '\n' is allowed after '\r': <seq>

Error message

only '\n' is allowed after '\r': <seq>

What it means

Vert.x validates HTTP header values to prevent header smuggling and malformed framing. When a header value contains a carriage return ('\r') that is not immediately followed by a line feed ('\n') — i.e. a bare CR — this IllegalArgumentException is thrown. Bare CR is not a legal line terminator in HTTP header values and can be used to inject headers.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java:763

        }
        return NO_CR_LF_STATE;
      }
    }
    if (state != NO_CR_LF_STATE) {
      // this is a rare scenario
      return validateCrLfChar(seq, state, ch);
    } else {
      return NO_CR_LF_STATE;
    }
  }

  private static int validateCrLfChar(CharSequence seq, int state, char ch) {
    switch (state) {
      case CR_STATE:
        if (ch == '\n') {
          return LF_STATE;
        }
        throw new IllegalArgumentException("only '\\n' is allowed after '\\r': " + seq);
      case LF_STATE:
        switch (ch) {
          case '\t':
          case ' ':
            // return to the normal state
            return NO_CR_LF_STATE;
          default:
            throw new IllegalArgumentException("only ' ' and '\\t' are allowed after '\\n': " + seq);
        }
      default:
        // this should never happen
        throw new AssertionError();
    }
  }

  private static void validateNonPrintableCtrlChar(CharSequence seq, int ch) {
    // The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR
    switch (ch) {

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Remove or replace bare '\r' characters from the header value (use '\n' only inside obs-fold sequences, or better, strip all line breaks).
  2. Sanitize the value before setting it, e.g. value.replaceAll("[\\r\\n]", " ").
  3. If obs-fold is intended, ensure the sequence is exactly CRLF followed by SP or HTAB ("\r\n ").

Example fix

// before
request.putHeader("X-Note", "line1\rline2"); // throws
// after
request.putHeader("X-Note", "line1\nline2".replace("\r", "")); // or replace line breaks with spaces
Defensive patterns

Strategy: validation

Validate before calling

public static void checkHeaderNoBareCr(String name, String value) {
  for (int i = 0; i < value.length(); i++) {
    if (value.charAt(i) == '\r' && (i + 1 >= value.length() || value.charAt(i + 1) != '\n')) {
      throw new IllegalArgumentException("bare CR in header " + name);
    }
  }
}

Try / catch

try {
  request.putHeader(name, value);
} catch (IllegalArgumentException e) {
  log.warn("Rejecting header {} : {}", name, e.getMessage());
  request.putHeader(name, sanitize(value));
}

Prevention

When it happens

Trigger: Calling request.putHeader(name, value) / HttpHeaders.set or any API that writes a header whose value contains a '\r' character that is not directly followed by '\n' (e.g. "a\rb", "a\r\tb"), triggered during header validation in HttpUtils.validateValueChar/validateSequenceHeaderValue.

Common situations: Building header values by joining multi-line data with '\r' line endings (e.g. Windows-style text or log data); copying a header value captured from raw CRLF-split bytes; template strings pasted from Windows editors that embedded CR characters.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/b87e258794055ec7. Report an issue: GitHub.