apache/hadoop · error · IOException

"Concat operation doesn't support " + FSDirectory.DOT_RESERV

Error message

"Concat operation doesn't support " + FSDirectory.DOT_RESERVED_STRING + " relative path : " + srcPath

What it means

Identical guard to the target-path check, but applied to each SOURCE path: concat refuses any src under /.reserved/raw or /.reserved/inodes. validatePath loops over every element of srcs and throws before target/source file verification begins. The rationale is the same — reserved paths are virtual views and cannot participate in namespace mutation.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirConcatOp.java:93

    }
    fsd.getEditLog().logConcat(target, srcs, timestamp, logRetryCache);
    return fsd.getAuditFileInfo(targetIIP);
  }

  private static void validatePath(String target, String[] srcs)
      throws IOException {
    Preconditions.checkArgument(!target.isEmpty(), "Target file name is empty");
    Preconditions.checkArgument(srcs != null && srcs.length > 0,
        "No sources given");
    if (FSDirectory.isReservedRawName(target)
        || FSDirectory.isReservedInodesName(target)) {
      throw new IOException("Concat operation doesn't support "
          + FSDirectory.DOT_RESERVED_STRING + " relative path : " + target);
    }
    for (String srcPath : srcs) {
      if (FSDirectory.isReservedRawName(srcPath)
          || FSDirectory.isReservedInodesName(srcPath)) {
        throw new IOException("Concat operation doesn't support "
            + FSDirectory.DOT_RESERVED_STRING + " relative path : " + srcPath);
      }
    }
  }

  private static void verifyTargetFile(FSDirectory fsd, final String target,
      final INodesInPath targetIIP) throws IOException {
    // check the target
    if (FSDirEncryptionZoneOp.getEZForPath(fsd, targetIIP) != null) {
      throw new HadoopIllegalArgumentException(
          "concat can not be called for files in an encryption zone.");
    }
    final INodeFile targetINode = INodeFile.valueOf(targetIIP.getLastINode(),
        target);
    if(targetINode.isUnderConstruction()) {
      throw new HadoopIllegalArgumentException("concat: target file "
          + target + " is under construction");
    }

View on GitHub (pinned to 2add963021)

Solutions

  1. Strip the reserved prefix from every source path before calling concat (map the srcs array through a normalizer).
  2. Keep two distinct path lists in EZ tooling: raw paths for reading bytes, plain paths for mutations — never interchange them.
  3. Add a unit assertion in your pipeline that no path passed to a mutating FileSystem API starts with /.reserved.

Example fix

// before
Path[] srcs = rawManifest.stream().map(Path::new).toArray(Path[]::new);
fs.concat(target, srcs);

// after
Path[] srcs = rawManifest.stream()
    .map(p -> new Path(p).toUri().getPath().replaceFirst("^/\\.reserved/(raw|inodes)", ""))
    .map(Path::new).toArray(Path[]::new);
fs.concat(target, srcs);
Defensive patterns

Strategy: validation

Validate before calling

static boolean isReservedPath(Path p) {
  String s = p.toUri().getPath();
  return s != null && (s.equals("/.reserved") || s.startsWith("/.reserved/"));
}
for (Path src : srcs) {
  if (isReservedPath(src)) throw new IllegalArgumentException("strip /.reserved from src: " + src);
}

Try / catch

catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("doesn't support .reserved")) {
    srcs = Arrays.stream(srcs).map(p -> stripReserved(p)).toArray(Path[]::new);
    fs.concat(target, srcs); // retry with cleaned sources
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling FileSystem.concat(target, srcs) where one or more entries in srcs contain the /.reserved/raw prefix — e.g. a manifest of raw paths produced by an encryption-zone-aware listing tool is fed straight into concat.

Common situations: Ingest pipelines that list an encryption zone through /.reserved/raw for verification and then reuse the same path list for compaction via concat; mixed toolchains where one component adds the prefix and another (correctly) does not.

Related errors


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