apache/hadoop · error · IOException

Update {} but the new block {} does not have a larger genera

Error message

Update {} but the new block {} does not have a larger generation stamp than the last block {}

What it means

updateBlock enforces generation-stamp monotonicity: the replacement block's GS must be strictly greater than the last block's current GS. A smaller or equal GS means the caller is applying stale recovery metadata, so the update is rejected with an IOException after a warn log.

Source

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

  private void updatePipelineInternal(String clientName, ExtendedBlock oldBlock,
      ExtendedBlock newBlock, DatanodeID[] newNodes, String[] newStorageIDs,
      boolean logRetryCache)
      throws IOException {
    assert hasWriteLock(RwLockMode.GLOBAL);
    // check the vadility of the block and lease holder name
    final INodeFile pendingFile = checkUCBlock(oldBlock, clientName);
    final String src = pendingFile.getFullPathName();
    final BlockInfo lastBlock = pendingFile.getLastBlock();
    assert !lastBlock.isComplete();

    // check new GS & length: this is not expected
    if (newBlock.getGenerationStamp() <= lastBlock.getGenerationStamp()) {
      final String msg = "Update " + oldBlock + " but the new block " + newBlock
          + " does not have a larger generation stamp than the last block "
          + lastBlock;
      LOG.warn(msg);
      throw new IOException(msg);
    }
    if (newBlock.getNumBytes() < lastBlock.getNumBytes()) {
      final String msg = "Update " + oldBlock + " (size="
          + oldBlock.getNumBytes() + ") to a smaller size block " + newBlock
          + " (size=" + newBlock.getNumBytes() + ")";
      LOG.warn(msg);
      throw new IOException(msg);
    }

    // Update old block with the new generation stamp and new length
    blockManager.updateLastBlock(lastBlock, newBlock);

    // find the DatanodeDescriptor objects
    final DatanodeStorageInfo[] storages = blockManager.getDatanodeManager()
        .getDatanodeStorageInfos(newNodes, newStorageIDs,
            "src=%s, oldBlock=%s, newBlock=%s, clientName=%s",
            src, oldBlock, newBlock, clientName);
    lastBlock.getUnderConstructionFeature().setExpectedLocations(lastBlock,

View on GitHub (pinned to 2add963021)

Solutions

  1. Re-fetch the current last block (getBlockLocations / ExtendedBlock) and build the update from its latest GS
  2. Ensure one recovery driver per block at a time
  3. Treat the error as 'state moved on': verify final state instead of blind retry
Defensive patterns

Strategy: retry

Try / catch

try {
  updateBlock(oldBlock, newBlock, ...);
} catch (IOException e) {
  if (e.getMessage().contains("does not have a larger generation stamp")) {
    LocatedBlock cur = dfs.getClient().getLastLocatedBlock(path);
    ExtendedBlock fixed = new ExtendedBlock(cur.getBlock().getBlockPoolId(),
        cur.getBlock().getBlockId(), newLen, cur.getBlock().getGenerationStamp() + 1);
    updateBlock(cur.getBlock(), fixed, ...); // rebuild from current GS
  } else { throw e; }
}

Prevention

When it happens

Trigger: Retrying updateBlock with a previously generated stamp after another recovery already advanced the block's GS; two concurrent recoveries computing updates off the same base state.

Common situations: Timeout-retry logic that reuses the old newBlock; races between a client and a lease-recovery thread updating the same last block.

Related errors


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