apache/hadoop · error · HadoopIllegalArgumentException

Missing storageIDs: It is likely that the HDFS client, who m

Error message

Missing storageIDs: It is likely that the HDFS client, who made this call, is running in an older version of Hadoop(pre-2.0.0-alpha)  which does not support storageIDs. datanodeID.length={datanodeID.length}

What it means

Thrown as HadoopIllegalArgumentException from DatanodeManager.getDatanodeStorageInfos when the datanodeID array and storageIDs array lengths differ; the specific 'Missing storageIDs' text appears when storageIDs is empty, which indicates a pre-2.0.0-alpha client that does not understand per-storage identifiers. Callers pass paired (datanode, storageID) lists — e.g., pipeline recovery and block token renewal — and an empty/short storageIDs list cannot identify which storage to act on.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java:841

                                    + e.getLocalizedMessage());
      throw e;
    }
    return node;
  }

  public DatanodeStorageInfo[] getDatanodeStorageInfos(
      DatanodeID[] datanodeID, String[] storageIDs,
      String format, Object... args) throws UnregisteredNodeException {
    storageIDs = storageIDs == null ? new String[0] : storageIDs;
    if (datanodeID.length != storageIDs.length) {
      // Error for pre-2.0.0-alpha clients.
      final String err = (storageIDs.length == 0?
          "Missing storageIDs: It is likely that the HDFS client,"
          + " who made this call, is running in an older version of Hadoop"
          + "(pre-2.0.0-alpha)  which does not support storageIDs."
          : "Length mismatched: storageIDs.length=" + storageIDs.length + " != "
          ) + " datanodeID.length=" + datanodeID.length;
      throw new HadoopIllegalArgumentException(
          err + ", "+ String.format(format, args));
    }
    if (datanodeID.length == 0) {
      return null;
    }
    final DatanodeStorageInfo[] storages = new DatanodeStorageInfo[datanodeID.length];
    for(int i = 0; i < datanodeID.length; i++) {
      if (datanodeID[i].equals(DatanodeID.EMPTY_DATANODE_ID)) {
        storages[i] = null;
        continue;
      }
      final DatanodeDescriptor dd = getDatanode(datanodeID[i]);
      if (dd != null) {
        storages[i] = dd.getStorageInfo(storageIDs[i]);
      }
    }
    return storages;
  }

View on GitHub (pinned to 2add963021)

Solutions

  1. Upgrade the client to a Hadoop 2.0.0-alpha+ (ideally cluster-matching) version so storageIDs are populated
  2. In custom code, always pass a storageIDs array of equal length, obtained from LocatedBlock.getLocatedBlocks() storageIDs
  3. If mid-upgrade, complete the rolling upgrade so all components speak the storage-aware protocol
  4. Verify with the exception's suffix (format/args) which call path produced it and check that client's version

Example fix

// before: building targets without storage IDs
DatanodeID[] dns = ...; String[] sids = null; // -> Missing storageIDs

// after: derive storageIDs from the located block
LocatedBlock lb = namenode.addBlock(src, clientName, previous, null, ...);
DatanodeID[] dns = toDatanodeID(lb.getLocations());
String[] sids = lb.getStorageIDs(); // same length as dns
namenode.updatePipeline(clientName, oldBlock, newBlock, dns, sids);
Defensive patterns

Strategy: validation

Validate before calling

// Always pass equal-length arrays derived from a LocatedBlock
DatanodeID[] dns = Arrays.stream(lb.getLocations()).map(DatanodeInfo::new).toArray(DatanodeID[]::new);
String[] storageIDs = lb.getStorageIDs();
assert dns.length == storageIDs.length && storageIDs.length > 0
    : "storageIDs missing — client/library too old or bad LocatedBlock";
nn.updatePipeline(clientName, oldBlock, newBlock, dns, storageIDs);

Try / catch

try {
  nn.updatePipeline(clientName, old, neu, dns, storageIDs);
} catch (HadoopIllegalArgumentException e) {
  if (e.getMessage().contains("storageIDs")) {
    // rebuild from a fresh LocatedBlock via addBlock; never mix old client arrays
    LocatedBlock lb = nn.addBlock(src, clientName, neu, null, null, null);
    nn.updatePipeline(clientName, old, lb.getBlock(), toIDs(lb), lb.getStorageIDs());
  } else { throw e; }
}

Prevention

When it happens

Trigger: An ancient client RPC (or code constructing these arrays without storageIDs) calls an API (e.g., updateBlockForPipeline/updatePipeline or DN-side getDatanodeStorageInfos usage) where datanodeID.length != storageIDs.length with storageIDs empty; length-mismatch variant also fires on partially built arrays.

Common situations: Mixing a pre-2.0 (0.20/1.x-era) client library with a modern cluster; custom tooling building DatanodeID[] but passing null/empty storageIDs; version-skew during rolling upgrades.

Related errors


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