apache/hadoop · error · java.io.IOException
Op {opCodeByte} has size {opLength}, but maxOpSize = {maxOpS
Error message
Op {opCodeByte} has size {opLength}, but maxOpSize = {maxOpSize} What it means
LengthPrefixedReader.decodeOpFrame() validates the record's 4-byte length before decoding: opLength = stored length + 5 (1 opcode byte + 4 checksum bytes). It must not exceed maxOpSize, configured by dfs.namenode.max.op.size (default 50 MB, DFSConfigKeys.java:1290). The guard exists because a garbage length used to drive a huge allocation and OOM the NameNode/JournalNode when reading corrupt data.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogOp.java:5249
byte opCodeByte;
try {
opCodeByte = in.readByte();
} catch (EOFException eof) {
// EOF at an opcode boundary is expected.
return HdfsServerConstants.INVALID_TXID;
}
if (opCodeByte == FSEditLogOpCodes.OP_INVALID.getOpCode()) {
verifyTerminator();
return HdfsServerConstants.INVALID_TXID;
}
// Here, we verify that the Op size makes sense and that the
// data matches its checksum before attempting to construct an Op.
// This is important because otherwise we may encounter an
// OutOfMemoryException which could bring down the NameNode or
// JournalNode when reading garbage data.
int opLength = in.readInt() + OP_ID_LENGTH + CHECKSUM_LENGTH;
if (opLength > maxOpSize) {
throw new IOException("Op " + (int)opCodeByte + " has size " +
opLength + ", but maxOpSize = " + maxOpSize);
} else if (opLength < MIN_OP_LENGTH) {
throw new IOException("Op " + (int)opCodeByte + " has size " +
opLength + ", but the minimum op size is " + MIN_OP_LENGTH);
}
long txid = in.readLong();
// Verify checksum
in.reset();
in.mark(maxOpSize);
checksum.reset();
for (int rem = opLength - CHECKSUM_LENGTH; rem > 0;) {
int toRead = Math.min(temp.length, rem);
IOUtils.readFully(in, temp, 0, toRead);
checksum.update(temp, 0, toRead);
rem -= toRead;
}
int expectedChecksum = in.readInt();
int calculatedChecksum = (int)checksum.getValue();View on GitHub (pinned to 2add963021)
Solutions
- Determine which case you are in with 'hdfs offlineEditsViewer -i <edits> -o out.xml' before changing anything
- If the op is legitimate, set dfs.namenode.max.op.size above the record size in hdfs-site.xml on the NameNode (and any tool reading the log) and restart
- If corrupt, run 'hdfs namenode -recover' to skip the record, or restore a healthy copy of the segment from QJM majority
Example fix
<!-- before: hdfs-site.xml (default cap = 50 MB) --> <!-- after --> <property> <name>dfs.namenode.max.op.size</name> <value>134217728</value> </property>
Defensive patterns
Strategy: retry
Validate before calling
# before replay of segments known to carry very large ops: # check largest segment size and raise the cap above it ls -l /dfs/name/current/edits_* # hdfs-site.xml: dfs.namenode.max.op.size must exceed the largest single record
Try / catch
try {
reader.readOp(); // maxOpSize from dfs.namenode.max.op.size
} catch (IOException e) {
if (e.getMessage().contains("but maxOpSize =")) {
if (offlineEditsViewerConfirmsLegitLargeOp) {
reader.setMaxOpSize(largerLimit); // or raise dfs.namenode.max.op.size and restart
// then retry the replay
} else {
// corruption: recover or restore a clean segment
}
} else { throw e; }
} Prevention
- Set dfs.namenode.max.op.size with headroom if the workload writes very large records
- Keep the cap at default otherwise — it is an OOM guard against corrupt length fields
- Validate suspicious segments with offlineEditsViewer before loosening the limit
When it happens
Trigger: A corrupt length int in the stream (bit rot, torn write, misalignment) produces an absurd opLength; rarely, a legitimate record larger than 50 MB (an extreme payload) exceeds the default cap on a stock configuration.
Common situations: Corrupt journal segments; clusters carrying pathologically large ops (huge concat/rename payloads) replayed with default settings; tools reading the same segments inherit the same limit.
Related errors
- Incorrect data format. ConcatDeleteOp can have at most {} so
- Op {opCodeByte} has size {opLength}, but the minimum op size
- Attempted to use QJM output buffer capacity (" + size + ") g
- The log file {} seems to contain valid transactions ; journa
- Same delegation token being added twice; invalid entry in fs
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/0211a8c28ab52b92.
Report an issue: GitHub.