apache/hadoop · error · IOException

Incorrect data format. ConcatDeleteOp cannot have a negative

Error message

Incorrect data format. ConcatDeleteOp cannot have a negative number of data  sources.

What it means

ConcatDeleteOp.readFields() derives the number of source paths (srcSize): in optimized layouts it is a 4-byte int read from the stream, in legacy layouts length-2. A negative srcSize cannot describe any record, so it is rejected as malformed data before allocating the sources array.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogOp.java:1325

        throws IOException {
      if (!NameNodeLayoutVersion.supports(
          LayoutVersion.Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
        this.length = in.readInt();
        if (length < 3) { // trg, srcs.., timestamp
          throw new IOException("Incorrect data format " +
              "for ConcatDeleteOp.");
        }
      }
      this.trg = FSImageSerialization.readString(in);
      int srcSize = 0;
      if (NameNodeLayoutVersion.supports(
          LayoutVersion.Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
        srcSize = in.readInt();
      } else {
        srcSize = this.length - 1 - 1; // trg and timestamp
      }
      if (srcSize < 0) {
          throw new IOException("Incorrect data format. "
              + "ConcatDeleteOp cannot have a negative number of data " +
              " sources.");
      } else if (srcSize > MAX_CONCAT_SRC) {
          throw new IOException("Incorrect data format. "
              + "ConcatDeleteOp can have at most " + MAX_CONCAT_SRC +
              " sources, but we tried to have " + (length - 3) + " sources.");
      }
      this.srcs = new String [srcSize];
      for(int i=0; i<srcSize;i++) {
        srcs[i]= FSImageSerialization.readString(in);
      }
      
      if (NameNodeLayoutVersion.supports(
          LayoutVersion.Feature.EDITLOG_OP_OPTIMIZATION, logVersion)) {
        this.timestamp = FSImageSerialization.readLong(in);
      } else {
        this.timestamp = readLong(in);
      }

View on GitHub (pinned to 2add963021)

Solutions

  1. Run 'hdfs namenode -recover' to skip the bad record and finish startup, then save a checkpoint
  2. Inspect with 'hdfs offlineEditsViewer' to confirm the txid and extent of damage
  3. Replace the segment from a healthy JournalNode copy or the last checkpoint + valid edits
Defensive patterns

Strategy: try-catch

Validate before calling

hdfs offlineEditsViewer -i <edits segment> -o /dev/null   # fails at the first malformed record

Try / catch

try {
  reader.readOp();
} catch (IOException e) {
  LOG.error("Malformed concat record in " + segment + " at txid " + reader.getLastTxId(), e);
  // retry the whole replay with 'hdfs namenode -recover' (skipBrokenEdits)
}

Prevention

When it happens

Trigger: A corrupt int where srcSize is read (bit rot, garbage after misalignment), or a legacy record whose length word was 0 or 1 so length-2 goes negative; typically follows an earlier truncated/misparsed record that shifted the stream position.

Common situations: Same family as the other legacy length checks: crash-torn writes, failing journal disk, segments read with the wrong layout version.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/61a5c72926211f29. Report an issue: GitHub.