apache/hadoop · error · ReplicaAlreadyExistsException

temp.getGenerationStamp() != expectedGs = {expectedGs}, temp

Error message

temp.getGenerationStamp() != expectedGs = {expectedGs}, temp={temp}

What it means

Before converting a TEMPORARY replica to RBW, FsDatasetImpl verifies the replica's generation stamp equals expectedGs taken from the ExtendedBlock. A mismatch (stale or advanced stamp) throws ReplicaAlreadyExistsException, preventing the pipeline from continuing against the wrong block incarnation.

Source

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

      final ReplicaInfo temp;
      {
        // get replica
        final ReplicaInfo r = volumeMap.get(b.getBlockPoolId(), blockId);
        if (r == null) {
          throw new ReplicaNotFoundException(
              ReplicaNotFoundException.NON_EXISTENT_REPLICA + b);
        }
        // check the replica's state
        if (r.getState() != ReplicaState.TEMPORARY) {
          throw new ReplicaAlreadyExistsException(
              "r.getState() != ReplicaState.TEMPORARY, r=" + r);
        }
        temp = r;
      }
      // check generation stamp
      if (temp.getGenerationStamp() != expectedGs) {
        throw new ReplicaAlreadyExistsException(
            "temp.getGenerationStamp() != expectedGs = " + expectedGs
                + ", temp=" + temp);
      }

      // TODO: check writer?
      // set writer to the current thread
      // temp.setWriter(Thread.currentThread());

      // check length
      final long numBytes = temp.getNumBytes();
      if (numBytes < visible) {
        throw new IOException(numBytes + " = numBytes < visible = "
            + visible + ", temp=" + temp);
      }
      // check volume
      final FsVolumeImpl v = (FsVolumeImpl) temp.getVolume();
      if (v == null) {
        throw new IOException("r.getVolume() = null, temp=" + temp);

View on GitHub (pinned to 2add963021)

Solutions

  1. Refresh located blocks so the GSs match, then retry the conversion/pipeline
  2. Ensure only one recovery incarnation runs at a time for the block
  3. If the temp replica's GS is stale leftovers, invalidate it and let re-replication replace it
  4. Run 'hdfs fsck' to reconcile replica GSs across DNs
Defensive patterns

Strategy: validation

Validate before calling

Replica r = fsDataset.getReplica(b.getBlockPoolId(), b.getBlockId());
if (r != null && r.getGenerationStamp() != b.getGenerationStamp()) {
  refetchLocatedBlockAndRebuildPipeline(); // GS moved on; do not convert this temp replica
  return;
}
fsDataset.convertTemporaryToRbw(b, visible);

Type guard

boolean gsMatches(Replica r, ExtendedBlock b) {
  return r != null && r.getGenerationStamp() == b.getGenerationStamp();
}

Try / catch

catch (ReplicaAlreadyExistsException e) {
  if (e.getMessage() != null && e.getMessage().contains("expectedGs")) {
    refetchLocatedBlockAndRetryOnce();
  } else { throw e; }
}

Prevention

When it happens

Trigger: convertTemporaryToRbw where the temp replica's GS differs from the block's GS - typically a recovery bumped the GS after the temp replica was created, and the client is driving a pipeline with mismatched stamps.

Common situations: Lease/block recovery racing a replication transfer; stale located blocks carrying an old GS; a client retry mixing ExtendedBlocks from different block incarnations.

Related errors


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