apache/hadoop · error · IOException

Unexpected BlockUCState: {} is {} but not UNDER_CONSTRUCTION

Error message

Unexpected BlockUCState: {} is {} but not UNDER_CONSTRUCTION

What it means

checkUCBlock found the block but its BlockUCState is not UNDER_CONSTRUCTION (already COMMITTED or COMPLETE), so a new generation stamp cannot be minted for it. The block has moved past the recoverable state the caller assumes.

Source

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

        file.getFileWithSnapshotFeature().isCurrentFileDeleted()) {
      return true;
    }
    return false;
  }

  private INodeFile checkUCBlock(ExtendedBlock block,
      String clientName) throws IOException {
    assert hasWriteLock(RwLockMode.GLOBAL);
    checkNameNodeSafeMode("Cannot get a new generation stamp and an "
        + "access token for block " + block);
    
    // check stored block state
    BlockInfo storedBlock = getStoredBlock(ExtendedBlock.getLocalBlock(block));
    if (storedBlock == null) {
      throw new IOException(block + " does not exist.");
    }
    if (storedBlock.getBlockUCState() != BlockUCState.UNDER_CONSTRUCTION) {
      throw new IOException("Unexpected BlockUCState: " + block
          + " is " + storedBlock.getBlockUCState()
          + " but not " + BlockUCState.UNDER_CONSTRUCTION);
    }
    
    // check file inode
    final INodeFile file = getBlockCollection(storedBlock);
    if (file == null || !file.isUnderConstruction() || isFileDeleted(file)) {
      throw new IOException("The file " + storedBlock + 
          " belonged to does not exist or it is not under construction.");
    }
    
    // check lease
    if (clientName == null
        || !clientName.equals(file.getFileUnderConstructionFeature()
            .getClientName())) {
      throw new LeaseExpiredException("Lease mismatch: " + block + 
          " is accessed by a non lease holder " + clientName); 
    }

View on GitHub (pinned to 2add963021)

Solutions

  1. Refresh block state (getBlockLocations) and if the file is closed, accept the earlier recovery as final
  2. If the file is still open, re-run recoverLease and continue from the new block state
  3. Serialize recovery attempts per file in client code
Defensive patterns

Strategy: retry

Validate before calling

LocatedBlock last = dfs.getClient().getLastLocatedBlock(path);
if (last != null && last.isBlockUnderConstruction()) { /* safe to request new GS */ }

Try / catch

try {
  nextGenerationStamp(block, clientName);
} catch (IOException e) {
  if (e.getMessage().contains("Unexpected BlockUCState")) {
    // state advanced (committed/completed): verify file state and move on
    if (dfs.isFileClosed(path)) { return; }
    dfs.recoverLease(path); // else restart recovery from current state
  } else { throw e; }
}

Prevention

When it happens

Trigger: Pipeline recovery racing block commit or file completion: the block got committed by a first (unacknowledged) attempt, or lease recovery elsewhere advanced the block state.

Common situations: Timeout-and-retry of updateBlock without checking state; two clients concurrently recovering the same file.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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