apache/dolphinscheduler · error · IllegalArgumentException
failed to download to
Error message
failed to download to ${fileDownloadPathNormalized} What it means
CosStorageOperator.download resolves the destination path under FileUtils.DATA_BASEDIR (the DS temp folder) and refuses to write anywhere else. If the normalized destination escapes that folder, it throws IllegalArgumentException to block path traversal outside the sandbox.
Solutions
- Pass a path RELATIVE to the DS temp folder as dstFilePath
- Strip/normalize '..' segments and any leading '/' from user-supplied destination paths before calling download
- If the file truly must go elsewhere, download into the temp folder then move it with your own code
Example fix
// before operator.download(srcPath, "/data/out/result.csv"); // after operator.download(srcPath, "resources/out/result.csv"); // stays inside DATA_BASEDIR
Defensive patterns
Strategy: validation
Validate before calling
Path base = Paths.get(FileUtils.DATA_BASEDIR).normalize().toAbsolutePath();
Path dst = base.resolve(userDst).normalize().toAbsolutePath();
if (!dst.startsWith(base)) throw new IllegalArgumentException("dst must be inside DS temp folder"); Try / catch
try {
operator.download(src, dst);
} catch (IllegalArgumentException e) {
log.error("Destination escaped DS temp folder: {}", dst);
} Prevention
- Always pass destinations relative to the DS temp folder
- Sanitize '..' and leading '/' from user-supplied paths
- Never concatenate raw user input into the destination path
When it happens
Trigger: Calling download(srcFilePath, dstFilePath) where dstFilePath resolves (after normalize().toAbsolutePath()) outside the dolphinscheduler temp base dir — e.g., an absolute dstFilePath like '/etc/foo' or a path containing enough '../' segments to escape.
Common situations: Passing an absolute destination path instead of a relative one; user-supplied resource paths containing '..'; misconfigured task output paths pointing to other system directories.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- directory: already exists
- file: already exists
- bucketName: is not exists, you need to create them by…
- bucketName: is not exists, you need to create them by…
- bucketName: is not exists, you need to create them by…
AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06).
Data as JSON: /api/errors/1221730a2e9e5fea.
Report an issue: GitHub.
Appendix: source
Thrown at dolphinscheduler-storage-plugin/dolphinscheduler-storage-cos/src/main/java/org/apache/dolphinscheduler/plugin/storage/cos/CosStorageOperator.java:145
throw new FileAlreadyExistsException("directory: " + cosKey + " already exists");
}
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(0L);
InputStream emptyContent = new ByteArrayInputStream(new byte[0]);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, cosKey, emptyContent, metadata);
cosClient.putObject(putObjectRequest);
}
@SneakyThrows
@Override
public void download(String srcFilePath, String dstFilePath, boolean overwrite) {
String cosKey = transformAbsolutePathToCOSKey(srcFilePath);
Path dsTempFolder = Paths.get(FileUtils.DATA_BASEDIR).normalize().toAbsolutePath();
Path fileDownloadPathNormalized = dsTempFolder.resolve(dstFilePath).normalize().toAbsolutePath();
if (!fileDownloadPathNormalized.startsWith(dsTempFolder)) {
// if the destination file path is NOT in DS temp folder (e.g., '/tmp/dolphinscheduler'),
// an IllegalArgumentException should be thrown.
throw new IllegalArgumentException("failed to download to " + fileDownloadPathNormalized);
}
File dstFile = fileDownloadPathNormalized.toFile();
if (dstFile.isDirectory()) {
Files.delete(dstFile.toPath());
} else {
FileUtils.createDirectoryWithPermission(dstFile.getParentFile().toPath(), FileUtils.PERMISSION_755);
}
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, cosKey);
Download download = cosTransferManager.download(getObjectRequest, dstFile);
download.waitForCompletion();
}
@Override
public boolean exists(String fileName) {
String cosKey = transformAbsolutePathToCOSKey(fileName);
return cosClient.doesObjectExist(bucketName, cosKey);
}View on GitHub (pinned to 02eac45a1b)