{"record":{"id":"333e4c0727846ffe","repo":"apache/hadoop","slug":"replica-replicainfo-already-exists-on-storage-t","errorCode":null,"errorMessage":"Replica {replicaInfo} already exists on storage {targetStorageType}","messagePattern":"Replica (.+?) already exists on storage (.+?)","errorType":"exception","errorClass":"ReplicaAlreadyExistsException","httpStatus":null,"severity":"warning","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsDatasetImpl.java","lineNumber":1097,"sourceCode":"   * @return Returns the Old replicaInfo\n   * @throws IOException\n   */\n  @Override\n  public ReplicaInfo moveBlockAcrossStorage(ExtendedBlock block,\n      StorageType targetStorageType, String targetStorageId)\n      throws IOException {\n    ReplicaInfo replicaInfo = getReplicaInfo(block);\n    if (replicaInfo.getState() != ReplicaState.FINALIZED) {\n      throw new ReplicaNotFoundException(\n          ReplicaNotFoundException.UNFINALIZED_REPLICA + block);\n    }\n    if (replicaInfo.getNumBytes() != block.getNumBytes()) {\n      throw new IOException(\"Corrupted replica \" + replicaInfo\n          + \" with a length of \" + replicaInfo.getNumBytes()\n          + \" expected length is \" + block.getNumBytes());\n    }\n    if (replicaInfo.getVolume().getStorageType() == targetStorageType) {\n      throw new ReplicaAlreadyExistsException(\"Replica \" + replicaInfo\n          + \" already exists on storage \" + targetStorageType);\n    }\n\n    if (replicaInfo.isOnTransientStorage()) {\n      // Block movement from RAM_DISK will be done by LazyPersist mechanism\n      throw new IOException(\"Replica \" + replicaInfo\n          + \" cannot be moved from storageType : \"\n          + replicaInfo.getVolume().getStorageType());\n    }\n\n    FsVolumeReference volumeRef = null;\n    boolean shouldConsiderSameMountVolume =\n        shouldConsiderSameMountVolume(replicaInfo.getVolume(),\n            targetStorageType, targetStorageId);\n    boolean useVolumeOnSameMount = false;\n\n    try (AutoCloseableLock lock = lockManager.readLock(LockLevel.BLOCK_POOl,\n        block.getBlockPoolId())) {","sourceCodeStart":1079,"sourceCodeEnd":1115,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsDatasetImpl.java#L1079-L1115","documentation":"Thrown as ReplicaAlreadyExistsException from FsDatasetImpl.moveBlockAcrossStorage when replicaInfo.getVolume().getStorageType() already equals targetStorageType. The move request is a no-op: the replica lives on the requested storage tier already. It is a distinct exception type so callers (mover/NameNode block scheduler) can treat 'already satisfied' differently from real failures.","triggerScenarios":"Calling FsDatasetSpi.moveBlockAcrossStorage with a target type equal to the replica's current volume type — e.g. mover scheduling the same block twice, or a policy transition where the replica was already migrated by an earlier pass (or was written on the right tier to begin with).","commonSituations":"Concurrent mover instances; NameNode re-issuing satisfied moves after a DN re-registration; policy changed back and forth (HOT→COLD→HOT); duplicate scheduling during block-scheduler iterations.","solutions":["Treat as success/no-op: catch ReplicaAlreadyExistsException in the caller and skip — do not count it as a move failure.","Ensure only one mover runs per cluster/path at a time (Mover CLI coordination).","Verify the block's actual placement with hdfs fsck -blocks -locations — if it already matches policy, the move queue is stale.","No remediation on the replica itself is needed; nothing is wrong with the data."],"exampleFix":"// before: treating every exception from move as fatal\ntry {\n  dataset.moveBlockAcrossStorage(block, StorageType.SSD, null);\n} catch (IOException e) {\n  LOG.error(\"move failed\", e);\n}\n\n// after: no-op case handled explicitly\ntry {\n  dataset.moveBlockAcrossStorage(block, StorageType.SSD, null);\n} catch (ReplicaAlreadyExistsException e) {\n  LOG.debug(\"Replica already on target storage type: {}\", block);\n}","handlingStrategy":"try-catch","validationCode":"// Skip the call entirely when the replica is already on target tier.\nReplicaInfo info = fsDataset.getReplica(\n    block.getBlockPoolId(), block.getBlockId());\nif (info != null\n    && info.getVolume().getStorageType() == targetStorageType) {\n  return info; // no-op: already satisfied\n}","typeGuard":null,"tryCatchPattern":"// ReplicaAlreadyExistsException is the explicit no-op signal: absorb it.\ntry {\n  fsDataset.moveBlockAcrossStorage(block, StorageType.DISK, null);\n} catch (ReplicaAlreadyExistsException e) {\n  LOG.debug(\"{} already on {}; nothing to do\", block, StorageType.DISK);\n  return; // success-equivalent\n}","preventionTips":["Compare current vs target storage type before issuing moves (idempotency guard).","Catch ReplicaAlreadyExistsException separately from IOException and treat it as success.","Run one mover per cluster path; duplicate movers generate most of these no-op exceptions."],"tags":["hadoop","hdfs","datanode","fsdataset","mover","idempotency","storage-policy"],"backgroundTag":"replica-already-exists","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}