stanfordnlp/CoreNLP · error · IllegalArgumentException

Too few columns: / (offset: )

Error message

Too few columns: <columnI>/<numColumns> (offset: <offset>)

What it means

Thrown by the same CSV/TSV line parser when a row ENDS with fewer fields than numColumns: at a newline outside quotes, columnI must equal numColumns-1, otherwise the line has too few columns. The exception reports columnI/numColumns and the offset of the line in the input.

Solutions

  1. Fix or remove the short/blank lines in the source file (check for a trailing empty line).
  2. Set numColumns to the true (consistent) column count of the data.
  3. Pre-filter lines: skip empty lines and validate field count before feeding the parser.
  4. If trailing fields are legitimately optional, pad short lines with empty strings before parsing.

Example fix

// before
List<String[]> cols = IOUtils.csvStringToColumns(IOUtils.slurpFileNoExceptions(f, "UTF-8"), 4);
// after
String[] rows = Arrays.stream(IOUtils.slurpFileNoExceptions(f, "UTF-8").split("\n"))
                     .filter(l -> !l.trim().isEmpty()).toArray(String[]::new);
for (String r : rows) {
  if (r.split(",").length != 4) throw new IllegalArgumentException("Bad row: " + r);
}
List<String[]> cols = IOUtils.csvStringToColumns(String.join("\n", rows), 4);
Defensive patterns

Strategy: validation

Validate before calling

String[] lines = csvText.split("\n", -1);
if (!lines[lines.length - 1].trim().isEmpty()) { /* no trailing newline artifact */ }
for (int i = 0; i < lines.length; i++) {
  if (lines[i].trim().isEmpty()) continue; // skip blank lines
  if (lines[i].split(",", -1).length != numColumns)
    throw new IllegalArgumentException("Line " + (i + 1) + " has wrong field count");
}

Try / catch

try {
  List<String[]> cols = IOUtils.csvStringToColumns(csvText, numColumns);
} catch (IllegalArgumentException e) {
  throw new DataFormatException("Short row in CSV (offset " + e.getMessage() + "): fix or skip line");
}

Prevention

When it happens

Trigger: Calling the CSV reader with a numColumns larger than some row's actual field count: short/truncated lines, trailing blank lines parsed as rows, a header row with fewer fields, or data rows with optional trailing fields omitted.

Common situations: Files exported with ragged rows (optional last column empty and dropped); a blank line at end of file being counted as a malformed row; schema changed from 4 to 5 columns but old data files still in the pipeline; manual edits deleting a trailing comma.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/57763300723cef40. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/io/IOUtils.java:1463

            //(case: field separator)
            if(inQuotes){
              buffer[columnI].append(',');
            } else {
              columnI += 1;
              if(columnI >= numColumns){
                throw new IllegalArgumentException("Too many columns: "+columnI+"/"+numColumns+" (offset: " + offset + ")");
              }
              buffer[columnI] = new StringBuilder();
            }
            break;
          case '\n':
            //(case: newline)
            if(inQuotes){
              buffer[columnI].append('\n');
            } else {
              //((error checks))
              if(columnI != numColumns-1){
                throw new IllegalArgumentException("Too few columns: "+columnI+"/"+numColumns+" (offset: " + offset + ")");
              }
              //((create line))
              String[] rtn = new String[buffer.length];
              for(int i=0; i<buffer.length; i++){ rtn[i] = buffer[i].toString(); }
              lines.add(rtn);
              //((update state))
              columnI = 0;
              buffer[columnI] = new StringBuilder();
            }
            break;
          case '\\':
            nextIsEscaped = true;
            break;
          default:
            buffer[columnI].append(csvContents[offset]);
        }
      }
    }

View on GitHub (pinned to 1b7edd19c4)