apache/hadoop · error · UnsupportedOperationException

Replica of type ${getState()} does not support getRecoveryID

Error message

Replica of type ${getState()} does not support getRecoveryID

What it means

Recovery IDs exist only for replicas under recovery (RBW/RWR/RUR track a recoveryId through truncate/commit flows). FinalizedProvidedReplica is a FINALIZED replica backed by external PROVIDED storage and carries no recovery ID, so getRecoveryID() throws UnsupportedOperationException.

Source

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

  @Override  // Object
  public int hashCode() {
    return super.hashCode();
  }

  @Override
  public String toString() {
    return super.toString();
  }

  @Override
  public ReplicaInfo getOriginalReplica() {
    throw new UnsupportedOperationException("Replica of type " + getState() +
        " does not support getOriginalReplica");
  }

  @Override
  public long getRecoveryID() {
    throw new UnsupportedOperationException("Replica of type " + getState() +
        " does not support getRecoveryID");
  }

  @Override
  public void setRecoveryID(long recoveryId) {
    throw new UnsupportedOperationException("Replica of type " + getState() +
        " does not support setRecoveryID");
  }

  @Override
  public ReplicaRecoveryInfo createInfo() {
    throw new UnsupportedOperationException("Replica of type " + getState() +
        " does not support createInfo");
  }
}

View on GitHub (pinned to 2add963021)

Solutions

  1. Narrow the call site: only read recovery IDs from replicas in RBW/RWR/RUR states (instanceof ReplicaUnderReconstruction or state checks).
  2. Do not include provided replicas in recovery handshakes; pick a local replica on another DataNode.
  3. Upgrade to a Hadoop version with provided-storage guards in the affected flow, and check the JIRA for your code path.
  4. In custom datasets, return a recovery-capable view only for replicas that actually track recovery.

Example fix

// before
long recoveryId = replica.getRecoveryID();

// after: state-check before reading recovery bookkeeping
if (replica.getState() == ReplicaState.RUR
    || replica.getState() == ReplicaState.RBW
    || replica.getState() == ReplicaState.RWR) {
  long recoveryId = replica.getRecoveryID();
} else {
  // FINALIZED / PROVIDED: no recovery ID exists
}
Defensive patterns

Strategy: type-guard

Type guard

static boolean hasRecoveryId(ReplicaInfo r) {
  ReplicaState s = r.getState();
  return s == ReplicaState.RBW || s == ReplicaState.RWR || s == ReplicaState.RUR;
}

Try / catch

try {
  long id = replica.getRecoveryID();
} catch (UnsupportedOperationException e) {
  // replica carries no recovery ID (FINALIZED/PROVIDED): pick another recovery candidate
}

Prevention

When it happens

Trigger: Block-recovery code calling getRecoveryID() on a replica that turns out to be a FinalizedProvidedReplica — e.g., recovery initiated for a block whose only local copy is PROVIDED, or generic code enumerating volume-map replicas and reading recovery IDs unconditionally.

Common situations: PROVIDED-storage clusters where recovery flows encounter provided replicas; monitoring or tooling code that assumes every replica supports the full ReplicaInfo API; version upgrades adding recovery call sites that lack provided-storage guards.

Related errors


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