juicedata/juicefs · error · HadoopIllegalArgumentException

Source file " + normalizePath(src) + " is no

Error message

Source file " + normalizePath(src)
                + " is not in the same directory with the target "
                + normalizePath(dst)

What it means

Thrown by concat() when a source path is not in the same parent directory as the destination. JuiceFS's native concat requires all files in the same directory, so the wrapper pre-validates each src's parent against dst's parent and rejects mismatches with HadoopIllegalArgumentException.

Source

Thrown at sdk/java/src/main/java/io/juicefs/JuiceFileSystemImpl.java:1612

  @Override
  public void concat(final Path dst, final Path[] srcs) throws IOException {
    if (needCheckPermission()) {
      access(dst.getParent(), FsAction.WRITE);
      access(dst, FsAction.WRITE);
      for (Path src : srcs) {
        access(src, FsAction.READ);
      }
      superGroupFileSystem.concat(dst, srcs);
      return;
    }
    statistics.incrementWriteOps(1);
    if (srcs.length == 0) {
      throw new IllegalArgumentException("No sources given");
    }
    Path dp = makeQualified(dst).getParent();
    for (Path src : srcs) {
      if (!makeQualified(src).getParent().equals(dp)) {
        throw new HadoopIllegalArgumentException("Source file " + normalizePath(src)
                + " is not in the same directory with the target "
                + normalizePath(dst));
      }
    }
    byte[][] srcbytes = new byte[srcs.length][];
    int bufsize = 0;
    for (int i = 0; i < srcs.length; i++) {
      srcbytes[i] = normalizePath(srcs[i]).getBytes("UTF-8");
      bufsize += srcbytes[i].length + 1;
    }
    Pointer buf = Memory.allocate(Runtime.getRuntime(lib), bufsize);
    long offset = 0;
    for (int i = 0; i < srcs.length; i++) {
      buf.put(offset, srcbytes[i], 0, srcbytes[i].length);
      buf.putByte(offset + srcbytes[i].length, (byte) 0);
      offset += srcbytes[i].length + 1;
    }
    int r = lib.jfs_concat(Thread.currentThread().getId(), handle, normalizePath(dst), buf, bufsize);

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Move/copy the source files into the destination directory before concat
  2. Choose a dst in the same directory as the sources
  3. Rename sources to the target directory via fs.rename before concatenating
  4. Batch sources per-directory and run one concat per directory

Example fix

// before
fs.concat(new Path("/data/out/final"), new Path[]{new Path("/tmp/part-0")});
// after
fs.rename(new Path("/tmp/part-0"), new Path("/data/out/part-0"));
fs.concat(new Path("/data/out/final"), new Path[]{new Path("/data/out/part-0")});
Defensive patterns

Strategy: validation

Validate before calling

Path dp = dst.getParent(); for (Path s : srcs) if (!s.getParent().equals(dp)) throw new IllegalArgumentException("source not in dst dir: " + s);

Type guard

boolean sameDir(Path dst, Path src) { return dst.getParent().equals(src.getParent()); }

Try / catch

try { fs.concat(dst, srcs); } catch (HadoopIllegalArgumentException e) { /* relocate sources then retry */ }

Prevention

When it happens

Trigger: concat(dst, src) where src lives in a different directory than dst; using relative paths resolved differently from the qualified dst; programmatically mixing paths from multiple directories.

Common situations: Merging part files spread across subdirectories; users expecting HDFS-like cross-directory concat; staging files in /tmp then concatenating into a final directory.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/6daa8d60dd5638f3. Report an issue: GitHub.