apache/hadoop · error · PathIOException
Too many matches
Error message
Too many matches
What it means
Thrown by CommandWithDestination.getRemoteDestination() when the DESTINATION argument of -put/-cp/-moveFromLocal/-appendToFile is a glob that expands to more than one path (PathData.expandAsGlob returns >1 items). A copy destination must resolve to exactly one path, so PathIOException is thrown with custom text 'Too many matches'.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/CommandWithDestination.java:218
* @param args is the list of arguments
* @throws PathIOException if path doesn't exist or matches too many times
*/
protected void getRemoteDestination(LinkedList<String> args)
throws IOException {
if (args.size() < 2) {
dst = new PathData(Path.CUR_DIR, getConf());
} else {
String pathString = args.removeLast();
// if the path is a glob, then it must match one and only one path
PathData[] items = PathData.expandAsGlob(pathString, getConf());
switch (items.length) {
case 0:
throw new PathNotFoundException(pathString);
case 1:
dst = items[0];
break;
default:
throw new PathIOException(pathString, "Too many matches");
}
}
}
@Override
protected void processArguments(LinkedList<PathData> args)
throws IOException {
// if more than one arg, the destination must be a directory
// if one arg, the dst must not exist or must be a directory
if (args.size() > 1) {
if (!dst.exists) {
throw new PathNotFoundException(dst.toString());
}
if (!dst.stat.isDirectory()) {
throw new PathIsNotDirectoryException(dst.toString());
}
} else if (dst.exists) {
if (!dst.stat.isDirectory() && !overwrite) {View on GitHub (pinned to 2add963021)
Solutions
- Point the destination at the directory itself without wildcards ('/data/' not '/data/*')
- Use a single explicit destination path or directory name that does not yet contain multiple matches
- Run 'hdfs dfs -ls <dest-glob>' first and confirm exactly one result before the copy
Example fix
# before hdfs dfs -put local.txt /data/* # after hdfs dfs -put local.txt /data/
Defensive patterns
Strategy: validation
Validate before calling
// destination glob must resolve to exactly one entry
FileStatus[] matches = fs.globStatus(dstPattern);
if (matches != null && matches.length > 1) {
throw new IOException("ambiguous destination, " + matches.length + " matches for " + dstPattern);
} Try / catch
try {
shellRun("-put", localSrc, dstPattern);
} catch (PathIOException e) {
if ("Too many matches".equals(e.getMessage())) {
// target the containing directory instead of its contents
shellRun("-put", localSrc, dstPattern.getParent() + "/");
} else throw e;
} Prevention
- Copy into the directory itself ('/data/') rather than globbing its contents ('/data/*')
- Treat any destination-side wildcard as a code smell in scripts
- Assert single-match with globStatus in wrappers before delegating
When it happens
Trigger: 'hdfs dfs -put local.txt /data/*' where /data contains several entries; a destination like '/logs/2026*' matching multiple log files; brace expansion '/out/{a,b}' resolving to two existing paths.
Common situations: Users globbing the destination out of habit from source-side usage; scripts reusing a wildcard for both src and dst; intending 'copy into a directory' while pointing at the directory's contents rather than the directory itself.
Related errors
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/538840153c3f5a03.
Report an issue: GitHub.