apache/hadoop · error · DiskBalancerException
INVALID_VOLUME
INVALID_VOLUME
Error message
Disk Balancer - Unable to find source volume: {}. SubmitPlan failed. What it means
While translating plan steps into DiskBalancerWorkItems, createWorkPlan() resolves each step's source volume UUID against the DataNode's live storageID-to-volume map (getStorageIDToVolumeBasePathMap()). If the source volume UUID is absent, the plan references storage that no longer exists on this node, and Result.INVALID_VOLUME is thrown with the missing volume's path in the message.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/DiskBalancer.java:530
*/
private void createWorkPlan(NodePlan plan) throws DiskBalancerException {
Preconditions.checkState(lock.isHeldByCurrentThread());
// Cleanup any residual work in the map.
workMap.clear();
Map<String, String> storageIDToVolBasePathMap =
getStorageIDToVolumeBasePathMap();
for (Step step : plan.getVolumeSetPlans()) {
String sourceVolUuid = step.getSourceVolume().getUuid();
String destVolUuid = step.getDestinationVolume().getUuid();
String sourceVolBasePath = storageIDToVolBasePathMap.get(sourceVolUuid);
if (sourceVolBasePath == null) {
final String errMsg = "Disk Balancer - Unable to find source volume: "
+ step.getSourceVolume().getPath() + ". SubmitPlan failed.";
LOG.error(errMsg);
throw new DiskBalancerException(errMsg,
DiskBalancerException.Result.INVALID_VOLUME);
}
String destVolBasePath = storageIDToVolBasePathMap.get(destVolUuid);
if (destVolBasePath == null) {
final String errMsg = "Disk Balancer - Unable to find dest volume: "
+ step.getDestinationVolume().getPath() + ". SubmitPlan failed.";
LOG.error(errMsg);
throw new DiskBalancerException(errMsg,
DiskBalancerException.Result.INVALID_VOLUME);
}
VolumePair volumePair = new VolumePair(sourceVolUuid,
sourceVolBasePath, destVolUuid, destVolBasePath);
createWorkPlan(volumePair, step);
}
}
/**View on GitHub (pinned to 2add963021)
Solutions
- Regenerate the plan so it reflects the current volume set, then submit.
- List the DataNode's current volumes (DataNode JMX FSDatasetStateInfo, `hdfs dfsadmin -report`) and confirm each step's source volume UUID still exists.
- If a volume was intentionally removed, discard the old plan — it cannot be patched by hand without breaking the plan hash.
- Verify the plan is being submitted to the same DataNode it was generated for.
Example fix
// before: submit a plan generated before a disk was replaced
diskBalancer.submitPlan(planID, version, planString, false);
// after: check every step's volumes against the live volume set first
Map<String, ?> volumes = dataset.getVolumeInfoMap(); // keyed by storageID
for (Step s : NodePlan.parseJson(planString).getVolumeSetPlans()) {
if (!volumes.containsKey(s.getSourceVolume().getUuid())) {
planString = generateFreshPlan(datanode); // volume set changed
break;
}
}
diskBalancer.submitPlan(planID, version, planString, false); Defensive patterns
Strategy: validation
Validate before calling
Map<String, ?> volumes = dataset.getVolumeInfoMap(); // storageID -> VolumeInfo
for (Step s : NodePlan.parseJson(planString).getVolumeSetPlans()) {
if (!volumes.containsKey(s.getSourceVolume().getUuid())) {
// a source volume no longer exists: regenerate the plan
}
} Try / catch
try {
diskBalancer.submitPlan(planID, version, plan, false);
} catch (DiskBalancerException e) {
if (e.getResult() == DiskBalancerException.Result.INVALID_VOLUME
&& e.getMessage().contains("source volume")) {
// volume set changed since planning: regenerate the plan
}
} Prevention
- Regenerate plans whenever disks are added, removed, or replaced
- Compare plan step volume UUIDs against DataNode JMX volume state before executing
- Execute plans on the same node and volume configuration they were generated against
When it happens
Trigger: submitPlan where a step's sourceVolumeUUID is not among the DataNode's current volumes: a disk was removed, failed, or replaced between `-plan` and `-execute`; the plan was generated against a different node's volume set; storage IDs changed after a reformat.
Common situations: Dead disk swapped out before the plan was executed; hot-removed volume; DataNode restarted with a reduced dfs.datanode.data.dir list; submitting a plan file that belongs to another machine.
Related errors
- Not a valid Boolean value for {property}
- has incompatible storage Id.
- MALFORMED_PLAN
- OLD_PLAN_SUBMITTED
- detachBlock:Block not found. ${this}
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/f70599a8267ecbf7.
Report an issue: GitHub.