{"record":{"id":"363f7cbdf75964f9","repo":"apache/hadoop","slug":"storage-type-s-already-exists-on-same-mount-s","errorCode":null,"errorMessage":"Storage type %s already exists on same mount: %s.","messagePattern":"Storage type (.+?) already exists on same mount: (.+?)\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsDatasetImpl.java","lineNumber":467,"sourceCode":"          \"Found duplicated storage UUID: %s in %s.\",\n          sd.getStorageUuid(), sd.getVersionFile());\n      LOG.error(errorMsg);\n      throw new IOException(errorMsg);\n    }\n    // Check if there is same storage type on the mount.\n    // Only useful when same disk tiering is turned on.\n    FsVolumeImpl volumeImpl = (FsVolumeImpl) ref.getVolume();\n    FsVolumeReference checkRef = volumes\n        .getMountVolumeMap()\n        .getVolumeRefByMountAndStorageType(\n            volumeImpl.getMount(), volumeImpl.getStorageType());\n    if (checkRef != null) {\n      final String errorMsg = String.format(\n          \"Storage type %s already exists on same mount: %s.\",\n          volumeImpl.getStorageType(), volumeImpl.getMount());\n      checkRef.close();\n      LOG.error(errorMsg);\n      throw new IOException(errorMsg);\n    }\n    volumeMap.mergeAll(replicaMap);\n    storageMap.put(sd.getStorageUuid(),\n        new DatanodeStorage(sd.getStorageUuid(),\n            DatanodeStorage.State.NORMAL,\n            storageType));\n    asyncDiskService.addVolume(volumeImpl);\n    volumes.addVolume(ref);\n  }\n\n  private void addVolume(Storage.StorageDirectory sd) throws IOException {\n    final StorageLocation storageLocation = sd.getStorageLocation();\n\n    // If IOException raises from FsVolumeImpl() or getVolumeMap(), there is\n    // nothing needed to be rolled back to make various data structures, e.g.,\n    // storageMap and asyncDiskService, consistent.\n    FsVolumeImpl fsVolume = new FsVolumeImplBuilder()\n                              .setDataset(this)","sourceCodeStart":449,"sourceCodeEnd":485,"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#L449-L485","documentation":"Thrown as IOException from FsDatasetImpl.addVolume when the same-disk-tiering mount check finds a volume already registered for the same mount point and StorageType. When multiple data dirs live on one mount, each (mount, storage type) pair may only be served by one volume; the check via volumes.getMountVolumeMap().getVolumeRefByMountAndStorageType(mount, storageType) returns an existing reference and this add is rejected. The reference is closed before throwing so no leak is left behind.","triggerScenarios":"Configuring dfs.datanode.data.dir with two dirs on the same mount that declare the same storage type, e.g. [DISK]/mnt/big/dn1 and [DISK]/mnt/big/dn2 where /mnt/big is one filesystem, while dfs.datanode.same-disk-tiering.enabled is active. addVolume for the second dir finds the first in the mount-volume map and throws.","commonSituations":"Squeezing multiple 'volumes' out of one large disk without distinct storage types; migrating from separate disks to LVM/single XFS and forgetting to merge dirs; enabling same-disk-tiering on a config that predates it; specifying [DISK]/ and [DISK]/data on the root filesystem.","solutions":["Identify the duplicate: the message names the storage type and mount; list all dfs.datanode.data.dir entries on that mount and their [TYPE] tags.","Keep exactly one dir per (mount, storage type): either merge the duplicate dirs into one, or retag one as a different type ([SSD]/[ARCHIVE]/[RAM_DISK]) if tiering on one disk is the goal.","Put each dir on its own real mount (separate disks/filesystems) if you intended independent volumes.","If you did not intend same-disk tiering, verify dfs.datanode.same-disk-tiering.enabled and the mount detection (df output) for those dirs, then restart the DataNode."],"exampleFix":"<!-- before: two DISK dirs on the same mount /mnt/big -->\n<property>\n  <name>dfs.datanode.data.dir</name>\n  <value>[DISK]/mnt/big/dn1,[DISK]/mnt/big/dn2</value>\n</property>\n\n<!-- after: one dir per (mount, storage type) -->\n<property>\n  <name>dfs.datanode.data.dir</name>\n  <value>[DISK]/mnt/big/dn1,[ARCHIVE]/mnt/big/dn2</value>\n</property>","handlingStrategy":"validation","validationCode":"// Before enabling same-disk-tiering, assert (mount, storageType) uniqueness.\nMap<String, String> mountToType = new HashMap<>();\nfor (String d : conf.getTrimmedStrings(\"dfs.datanode.data.dir\")) {\n  Matcher m = Pattern.compile(\"^\\[([A-Z_]+)\\](.*)$\").matcher(d);\n  String type = m.matches() ? m.group(1) : \"DISK\";\n  File f = new File(m.matches() ? m.group(2) : d).getAbsoluteFile();\n  String mount = Files.getFileStore(f.toPath()).name();\n  String prev = mountToType.putIfAbsent(mount + \":\" + type, d);\n  if (prev != null) {\n    throw new IOException(type + \" declared twice on mount \" + mount\n        + \": \" + prev + \" and \" + d);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Design rule: one dir per (mount, storage type); distinct types per dir when multiple dirs share a mount.","Verify with df --output=target <dir> that 'separate' dirs are truly separate filesystems.","Re-validate config after hardware changes (LVM merges, disk replacements) before restarting the DataNode.","Keep same-disk-tiering configs documented so operators know multiple dirs on one mount are intentional and type-tagged."],"tags":["hadoop","hdfs","datanode","fsdataset","same-disk-tiering","storage-type","mount"],"backgroundTag":"storage-type-conflict-on-mount","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}