elastic/elasticsearch · error · IllegalArgumentException

Incomplete CEF header

Error message

Incomplete CEF header

What it means

IllegalArgumentException(INCOMPLETE_CEF_HEADER) from parseHeaders after the CEF prefix is confirmed valid but the pipe-splitting did not yield exactly 7 header fields. CEF defines seven mandatory header fields (Version, DeviceVendor, DeviceProduct, DeviceVersion, SignatureID, Name, Severity); missing or extra pipes both fail.

Source

Thrown at modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/CefParser.java:321

                i++; // and skip the next character
            } else if (curr == '|') { // a pipe, it's the end of a header
                headers.add(buffer.toString()); // emit the header
                buffer = new StringBuilder(); // and reset the buffer
                if (headers.size() == 7) {
                    extensionStart = i + 1; // the extensions begin after this pipe
                    break; // we've processed all the headers, so exit the loop
                }
            } else { // any other character
                buffer.append(curr); // is just added to the header
            }
        }

        if (headers.isEmpty() || headers.getFirst().startsWith("CEF:") == false) {
            throw new IllegalArgumentException(INVALID_CEF_FORMAT);
        }

        if (headers.size() != 7) {
            throw new IllegalArgumentException(INCOMPLETE_CEF_HEADER);
        }

        // for simplicity of the interface, pack the unparsed extension string itself into the returned list of headers
        String extensionString = cefString.substring(extensionStart);
        headers.add(extensionString);

        return headers;
    }

    private static void processHeaders(List<String> headers, CefEvent event) {
        for (int i = 0; i < headers.size(); i++) {
            final String value = headers.get(i);
            switch (i) {
                case 0 -> event.addCefMapping("version", value.substring(4));
                case 1 -> {
                    event.addCefMapping("device.vendor", value);
                    event.addRootMapping("observer.vendor", value);
                }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Escape literal pipe characters in field values as '\|' per CEF spec
  2. Ensure all seven header fields are present, even if empty (emit empty fields as consecutive pipes)
  3. Validate the header count on the producer side before sending

Example fix

// before: only 6 fields (missing severity) -> incomplete
"CEF:0|Vendor|Product|1.0|100|Name|"
// after: 7 fields with severity
"CEF:0|Vendor|Product|1.0|100|Name|6|ext=..."
Defensive patterns

Strategy: validation

Validate before calling

// Validate seven headers before relying on the CEF processor:
long pipes = input.chars().filter(c -> c == '|').count();
// note: unescaped pipes only; do a proper escape-aware count in production
if (pipes < 6) throw new IllegalArgumentException("Incomplete CEF header");

Try / catch

try { cefProcessor.execute(doc); }
catch (IllegalArgumentException e) {
    if ("Incomplete CEF header".equals(e.getMessage())) { quarantine(doc); }
    else throw e;
}

Prevention

When it happens

Trigger: Input starts with 'CEF:' but contains fewer or more than 6 unescaped pipe separators before the extension block. Line 320 check (headers.size() != 7) fires.

Common situations: Producer omits an empty field (writes 'CEF:0|v|p||1.0|...' missing a pipe); unescaped pipe inside a field value; extra trailing pipe; version of producer with non-standard field count.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/9d470b7f1b1a6067. Report an issue: GitHub.