apache/hadoop · error · IllegalArgumentException

Missing a valid replica to recover from

Error message

Missing a valid replica to recover from

What it means

ReplicaBuilder.buildRUR() creates a ReplicaUnderRecovery - a wrapper that tracks an existing replica through the recovery handshake. Unlike other build paths it has no from-scratch fallback: it requires from(replica), and a null source throws IllegalArgumentException 'Missing a valid replica to recover from'.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/ReplicaBuilder.java:296

    if (null != fromReplica && fromReplica.getState() == ReplicaState.RWR) {
      return new ReplicaWaitingToBeRecovered(
          (ReplicaWaitingToBeRecovered) fromReplica);
    } else if (null != fromReplica){
      throw new IllegalArgumentException("Incompatible fromReplica "
          + "state: " + fromReplica.getState());
    } else {
      if (null != block) {
        return new ReplicaWaitingToBeRecovered(block, volume, directoryUsed);
      } else {
        return new ReplicaWaitingToBeRecovered(blockId, length, genStamp,
            volume, directoryUsed);
      }
    }
  }

  private LocalReplica buildRUR() throws IllegalArgumentException {
    if (null == fromReplica) {
      throw new IllegalArgumentException(
          "Missing a valid replica to recover from");
    }
    if (null != writer || null != block) {
      throw new IllegalArgumentException("Invalid state for "
          + "recovering from replica with blk id "
          + fromReplica.getBlockId());
    }
    if (fromReplica.getState() == ReplicaState.RUR) {
      return new ReplicaUnderRecovery((ReplicaUnderRecovery) fromReplica);
    } else {
      return new ReplicaUnderRecovery(fromReplica, recoveryId);
    }
  }

  private ProvidedReplica buildProvidedFinalizedReplica()
      throws IllegalArgumentException {
    ProvidedReplica info = null;
    if (fromReplica != null) {

View on GitHub (pinned to 2add963021)

Solutions

  1. Always call .from(replica) with the live replica being recovered before building RUR.
  2. Re-fetch the replica from ReplicaMap/FsVolumeReference right before .from() and fail the recovery cleanly if absent.
  3. If the replica vanished (invalidated concurrently), abort recovery for that block instead of constructing RUR.
  4. Add a null-check precondition with block context in your wrapper.

Example fix

// before
ReplicaUnderRecovery rur = (ReplicaUnderRecovery) new ReplicaBuilder(ReplicaState.RUR)
    .setRecoveryId(recoveryId).build();

// after
Preconditions.checkNotNull(source,
    "cannot recover block %s: replica not found", blockId);
ReplicaUnderRecovery rur = (ReplicaUnderRecovery) new ReplicaBuilder(ReplicaState.RUR)
    .from(source)
    .setRecoveryId(recoveryId).build();
Defensive patterns

Strategy: validation

Validate before calling

Preconditions.checkNotNull(source,
    "cannot recover block %s: replica not found", blockId);
ReplicaUnderRecovery rur = (ReplicaUnderRecovery) new ReplicaBuilder(ReplicaState.RUR)
    .from(source)
    .setRecoveryId(recoveryId).build();

Try / catch

try {
  rur = (ReplicaUnderRecovery) builder.build();
} catch (IllegalArgumentException e) {
  throw new IOException("RUR setup failed for block " + blockId + ": "
      + e.getMessage(), e);
}

Prevention

When it happens

Trigger: new ReplicaBuilder(ReplicaState.RUR).setRecoveryId(id).build() (or a direct buildRUR call) without .from(existingReplica) - recovery was initiated without identifying which replica is being recovered.

Common situations: Block-recovery code paths or tests that build RUR replicas from IDs/fields only; races where the source replica was removed (invalidated) from the volume map before recovery was set up, leaving null to feed the builder.

Related errors


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