apache/druid · error · IllegalArgumentException

Cannot accept both [findColumnsFromHeader] and [hasHeaderRow

Error message

Cannot accept both [findColumnsFromHeader] and [hasHeaderRow]

What it means

FlatTextInputFormat's constructor rejects configurations that supply both the legacy 'hasHeaderRow' flag and the newer 'findColumnsFromHeader' flag, because their combination is ambiguous. Only one header-detection mechanism may be given.

Source

Thrown at processing/src/main/java/org/apache/druid/data/input/impl/FlatTextInputFormat.java:67

  private final boolean tryParseNumbers;

  FlatTextInputFormat(
      @Nullable List<String> columns,
      @Nullable String listDelimiter,
      String delimiter,
      @Nullable Boolean hasHeaderRow,
      @Nullable Boolean findColumnsFromHeader,
      int skipHeaderRows,
      @Nullable Boolean tryParseNumbers
  )
  {
    this.columns = columns == null ? Collections.emptyList() : columns;
    this.listDelimiter = listDelimiter;
    this.delimiter = Preconditions.checkNotNull(delimiter, "delimiter");
    if (columns == null || columns.isEmpty()) {
      if (hasHeaderRow != null && findColumnsFromHeader != null) {
        // User provided both hasHeaderRow and findColumnsFromHeader.
        throw new IAE("Cannot accept both [findColumnsFromHeader] and [hasHeaderRow]");
      } else if (hasHeaderRow == null && findColumnsFromHeader == null) {
        // User provided neither columns, nor one of the header-related parameters.
        throw new IAE("Either [columns] or [findColumnsFromHeader] must be set");
      } else {
        // User provided one of hasHeaderRow or findColumnsFromHeader. Take the one they provided.
        this.findColumnsFromHeader = hasHeaderRow != null ? hasHeaderRow : findColumnsFromHeader;
      }
    } else {
      this.findColumnsFromHeader = findColumnsFromHeader == null ? false : findColumnsFromHeader;
    }
    this.skipHeaderRows = skipHeaderRows;
    Preconditions.checkArgument(
        !delimiter.equals(listDelimiter),
        "Cannot have same delimiter and list delimiter of [%s]",
        delimiter
    );
    this.tryParseNumbers = tryParseNumbers == null ? false : tryParseNumbers;

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Remove 'hasHeaderRow' and keep only 'findColumnsFromHeader' (current API)
  2. Or remove 'findColumnsFromHeader' if intentionally using the legacy 'hasHeaderRow'
  3. Alternatively specify an explicit 'columns' list, which bypasses both flags

Example fix

// before
{"type":"csv","hasHeaderRow":true,"findColumnsFromHeader":true}
// after
{"type":"csv","findColumnsFromHeader":true}
Defensive patterns

Strategy: validation

Validate before calling

// Before submitting the spec
Map<String,Object> fmt = (Map<String,Object>) spec.get("inputFormat");
if (fmt.get("hasHeaderRow") != null && fmt.get("findColumnsFromHeader") != null) {
    fmt.remove("hasHeaderRow"); // prefer the modern flag
}

Try / catch

try { new FlatTextInputFormat(columns, listDelimiter, delimiter, hasHeaderRow, findColumnsFromHeader, skipHeaderRows); } catch (IAE e) { /* strip one header flag and retry */ }

Prevention

When it happens

Trigger: Constructing FlatTextInputFormat (or submitting a JSON ingestion spec with a csv/tsv inputFormat) where 'columns' is null/empty AND both 'hasHeaderRow' and 'findColumnsFromHeader' are non-null.

Common situations: Upgrading specs written for older Druid versions (which used hasHeaderRow) and adding findColumnsFromHeader without removing the old field; copy-pasting examples that mix the two options.

Understand the failure class

Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/9d5c00ac83591d5c. Report an issue: GitHub.