apache/hadoop · warning · ReplicaNotFoundException

Cannot append to an unfinalized replica {block}

Error message

Cannot append to an unfinalized replica {block}

What it means

Thrown as ReplicaNotFoundException (UNFINALIZED_REPLICA prefix, 'Cannot append to an unfinalized replica') from FsDatasetImpl.moveBlockAcrossStorage(ExtendedBlock, StorageType, String) when the resolved replica's state is not FINALIZED — i.e. it is RBW (being written), RWR (recovered write), TEMP, or RUR. Storage-type moves only apply to finalized replicas, because unfinalized files are still owned by an active writer.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsDatasetImpl.java:1088

          + dstMeta, e);
    }
    LOG.debug("Linked {} to {} . Dest meta file: {}", srcReplicaUri, dstFile,
        dstMeta);
    return new File[]{dstMeta, dstFile};
  }

  /**
   * Move block files from one storage to another storage.
   * @return Returns the Old replicaInfo
   * @throws IOException
   */
  @Override
  public ReplicaInfo moveBlockAcrossStorage(ExtendedBlock block,
      StorageType targetStorageType, String targetStorageId)
      throws IOException {
    ReplicaInfo replicaInfo = getReplicaInfo(block);
    if (replicaInfo.getState() != ReplicaState.FINALIZED) {
      throw new ReplicaNotFoundException(
          ReplicaNotFoundException.UNFINALIZED_REPLICA + block);
    }
    if (replicaInfo.getNumBytes() != block.getNumBytes()) {
      throw new IOException("Corrupted replica " + replicaInfo
          + " with a length of " + replicaInfo.getNumBytes()
          + " expected length is " + block.getNumBytes());
    }
    if (replicaInfo.getVolume().getStorageType() == targetStorageType) {
      throw new ReplicaAlreadyExistsException("Replica " + replicaInfo
          + " already exists on storage " + targetStorageType);
    }

    if (replicaInfo.isOnTransientStorage()) {
      // Block movement from RAM_DISK will be done by LazyPersist mechanism
      throw new IOException("Replica " + replicaInfo
          + " cannot be moved from storageType : "
          + replicaInfo.getVolume().getStorageType());
    }

View on GitHub (pinned to 2add963021)

Solutions

  1. Close/wait for writers of the file (lease expiry or app completion) and re-run the mover — finalized replicas move fine.
  2. Check replica state on the DN: the exception text includes the replica (toString carries state, e.g. RBW/RWR); confirm with the DN's block report for that block.
  3. If the replica is stuck RWR/RUR after a dead writer, recover the lease (hdfs debug recoverLease) to finalize it, then move.
  4. This is transient for the mover — it logs and retries later; no data is at risk.
Defensive patterns

Strategy: validation

Validate before calling

// Check replica state before requesting a cross-storage move.
ReplicaInfo info = fsDataset.getReplica(
    block.getBlockPoolId(), block.getBlockId());
if (info == null || info.getState() != ReplicaState.FINALIZED) {
  // skip this block; the mover will revisit once writes finish
  continue;
}

Try / catch

// Treat unfinalized as 'try later', matching mover semantics.
try {
  fsDataset.moveBlockAcrossStorage(block, StorageType.ARCHIVE, null);
} catch (ReplicaNotFoundException e) {
  if (e.getMessage().contains("unfinalized")) {
    LOG.debug("Block {} not finalized yet; deferring move", block);
    deferForNextPass(block);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: NameNode/mover requests a storage-policy move (setStoragePolicy + Mover, or fast move during block scheduling) for a block whose local replica is mid-write: an open file's block, a block under lease recovery, or a replica still in RBW after a pipeline failure.

Common situations: Mover run while a job is actively writing the file; setStoragePolicy applied to open files; HDFS-9913-era fast move racing a replication recovery; block scanner-triggered moves of recently recovered RWR replicas.

Related errors


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