apache/hadoop · error · IOException

No directory is specified.

Error message

No directory is specified.

What it means

parseChangedVolumes builds StorageLocations from the submitted dfs.datanode.data.dir value; if the parse yields zero locations it throws IOException("No directory is specified.") and the live volume refresh (refreshVolumes, driven by reconfiguring dfs.datanode.data.dir) aborts before touching any volume. The value must be a comma-separated list with at least one valid [TYPE]scheme://path entry.

Source

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

    List<StorageLocation> unchangedLocations = Lists.newArrayList();
  }

  /**
   * Parse the new DFS_DATANODE_DATA_DIR value in the configuration to detect
   * changed volumes.
   * @param newVolumes a comma separated string that specifies the data volumes.
   * @return changed volumes.
   * @throws IOException if none of the directories are specified in the
   * configuration, or the storage type of a directory is changed.
   */
  @VisibleForTesting
  ChangedVolumes parseChangedVolumes(String newVolumes) throws IOException {
    Configuration conf = new Configuration();
    conf.set(DFS_DATANODE_DATA_DIR_KEY, newVolumes);
    List<StorageLocation> newStorageLocations = getStorageLocations(conf);

    if (newStorageLocations.isEmpty()) {
      throw new IOException("No directory is specified.");
    }

    // Use the existing storage locations from the current conf
    // to detect new storage additions or removals.
    Map<String, StorageLocation> existingStorageLocations = new HashMap<>();
    for (StorageLocation loc : getStorageLocations(getConf())) {
      existingStorageLocations.put(loc.getNormalizedUri().toString(), loc);
    }

    ChangedVolumes results = new ChangedVolumes();
    results.newLocations.addAll(newStorageLocations);

    for (Iterator<Storage.StorageDirectory> it = storage.dirIterator();
         it.hasNext(); ) {
      Storage.StorageDirectory dir = it.next();
      boolean found = false;
      for (Iterator<StorageLocation> newLocationItr =
           results.newLocations.iterator(); newLocationItr.hasNext();) {

View on GitHub (pinned to 2add963021)

Solutions

  1. Resubmit with at least one valid entry — the value is the complete desired volume set, e.g. [DISK]file:///data/dn1
  2. To remove volumes, list only the directories to KEEP; never an empty string
  3. To retire the very last volume, decommission the DataNode instead of live-removing it

Example fix

// before
$ hdfs dfsadmin -reconfig datanode dn1:9867 start ... dfs.datanode.data.dir=
// => IOException: No directory is specified.
// after
$ hdfs dfsadmin -reconfig datanode dn1:9867 start ... dfs.datanode.data.dir=[DISK]file:///data/dn1
Defensive patterns

Strategy: validation

Validate before calling

Configuration c = new Configuration(false);
c.set(DFS_DATANODE_DATA_DIR_KEY, newVolumes);
if (DataNode.getStorageLocations(c).isEmpty()) {
  throw new IllegalArgumentException("new dfs.datanode.data.dir parses to zero locations");
}

Try / catch

try {
  dn.refreshVolumes? // internal; externally: reconfigure dfs.datanode.data.dir
} catch (ReconfigurationException e) {
  if (String.valueOf(e.getCause()).contains("No directory is specified")) { /* resubmit full desired volume list */ }
}

Prevention

When it happens

Trigger: Submitting dfs.datanode.data.dir="", ",", whitespace, or entries that all fail URI parsing via 'hdfs dfsadmin -reconfig datanode ... start' or the reconfig JMX API; an unexpanded ${DATANODE_DIRS} placeholder renders to a single invalid location string.

Common situations: Ansible/Chef templates rendering an empty string when a variable is undefined; a 'remove volumes' attempt that blanks the field instead of listing the surviving dirs; CM/Ambari UI fields accidentally cleared before apply.

Related errors


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