{"record":{"id":"0211a8c28ab52b92","repo":"apache/hadoop","slug":"op-opcodebyte-has-size-oplength-but-maxopsize","errorCode":null,"errorMessage":"Op {opCodeByte} has size {opLength}, but maxOpSize = {maxOpSize}","messagePattern":"Op (.+?) has size (.+?), but maxOpSize = (.+?)","errorType":"exception","errorClass":"java.io.IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogOp.java","lineNumber":5249,"sourceCode":"      byte opCodeByte;\n      try {\n        opCodeByte = in.readByte();\n      } catch (EOFException eof) {\n        // EOF at an opcode boundary is expected.\n        return HdfsServerConstants.INVALID_TXID;\n      }\n      if (opCodeByte == FSEditLogOpCodes.OP_INVALID.getOpCode()) {\n        verifyTerminator();\n        return HdfsServerConstants.INVALID_TXID;\n      }\n      // Here, we verify that the Op size makes sense and that the\n      // data matches its checksum before attempting to construct an Op.\n      // This is important because otherwise we may encounter an\n      // OutOfMemoryException which could bring down the NameNode or\n      // JournalNode when reading garbage data.\n      int opLength =  in.readInt() + OP_ID_LENGTH + CHECKSUM_LENGTH;\n      if (opLength > maxOpSize) {\n        throw new IOException(\"Op \" + (int)opCodeByte + \" has size \" +\n            opLength + \", but maxOpSize = \" + maxOpSize);\n      } else  if (opLength < MIN_OP_LENGTH) {\n        throw new IOException(\"Op \" + (int)opCodeByte + \" has size \" +\n            opLength + \", but the minimum op size is \" + MIN_OP_LENGTH);\n      }\n      long txid = in.readLong();\n      // Verify checksum\n      in.reset();\n      in.mark(maxOpSize);\n      checksum.reset();\n      for (int rem = opLength - CHECKSUM_LENGTH; rem > 0;) {\n        int toRead = Math.min(temp.length, rem);\n        IOUtils.readFully(in, temp, 0, toRead);\n        checksum.update(temp, 0, toRead);\n        rem -= toRead;\n      }\n      int expectedChecksum = in.readInt();\n      int calculatedChecksum = (int)checksum.getValue();","sourceCodeStart":5231,"sourceCodeEnd":5267,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogOp.java#L5231-L5267","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"<!-- before: hdfs-site.xml (default cap = 50 MB) -->\n<!-- after -->\n<property>\n  <name>dfs.namenode.max.op.size</name>\n  <value>134217728</value>\n</property>","handlingStrategy":"retry","validationCode":"# before replay of segments known to carry very large ops:\n# check largest segment size and raise the cap above it\nls -l /dfs/name/current/edits_*\n# hdfs-site.xml: dfs.namenode.max.op.size must exceed the largest single record","typeGuard":null,"tryCatchPattern":"try {\n  reader.readOp(); // maxOpSize from dfs.namenode.max.op.size\n} catch (IOException e) {\n  if (e.getMessage().contains(\"but maxOpSize =\")) {\n    if (offlineEditsViewerConfirmsLegitLargeOp) {\n      reader.setMaxOpSize(largerLimit); // or raise dfs.namenode.max.op.size and restart\n      // then retry the replay\n    } else {\n      // corruption: recover or restore a clean segment\n    }\n  } else { throw e; }\n}","preventionTips":["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"],"tags":["hdfs","edit-log","corruption","configuration","limits"],"backgroundTag":"message-size-limit-exceeded","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}