alibaba/canal · error · RuntimeException
Failed to read file
Error message
Failed to read file
What it means
Thrown by FileUtils.validateFileName() when getCanonicalPath() throws an IOException during path resolution. This wraps the underlying I/O error (which may be caused by the base directory not existing, a broken symlink, permission denied, or filesystem-level errors) rather than the path-traversal check itself.
Source
Thrown at common/src/main/java/com/alibaba/otter/canal/common/utils/FileUtils.java:112
*
* @param baseDir
* @param destination
* @return
*/
public static String validateFileName(String baseDir, String destination) {
try {
// 验证 destination 是否在允许的基目录范围内
String basePath = new File(baseDir).getCanonicalPath();
String fullPath = new File(basePath, destination).getCanonicalPath();
// 检查 fullPath 是否以 basePath 开头
if (!fullPath.startsWith(basePath + File.separator)) {
throw new IllegalArgumentException("Invalid destination path");
}
return fullPath;
} catch (IOException e) {
throw new RuntimeException("Failed to read file", e);
}
}
public static void main(String[] args) throws IOException {
String fullPath = validateFileName("/tmp/", "1.txt");
System.out.println(fullPath);
System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));
fullPath = validateFileName("/tmp/", "test");
fullPath = validateFileName(fullPath,"1.txt");
System.out.println(fullPath);
System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));
fullPath = validateFileName("/tmp/", "../etc/hosts");
System.out.println(fullPath);
System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));
}View on GitHub (pinned to 87be50e876)
Solutions
- Verify that baseDir exists and is accessible: check with `ls -la baseDir` and confirm the JVM process has read/execute permissions.
- Ensure all symlinks in the path chain resolve to existing targets.
- In containerized deployments, confirm volume mounts are correctly configured and the path matches the canal configuration.
- Check the canal.instance/conf directory path in canal.properties — correct it if the deployment layout differs from the default.
Example fix
// before — baseDir does not exist canal.conf.dir = /opt/canal/conf // missing or not mounted // after — correct path canal.conf.dir = /home/admin/canal-server/conf
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify baseDir exists and is accessible before calling validateFileName
File base = new File(baseDir);
if (!base.exists() || !base.isDirectory()) {
throw new FileNotFoundException("Base directory does not exist: " + baseDir);
}
if (!base.canRead()) {
throw new SecurityException("Cannot read base directory: " + baseDir);
} Type guard
null
Try / catch
try {
String path = FileUtils.validateFileName(baseDir, destination);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("Failed to read file")) {
logger.error("Cannot resolve canonical path for baseDir={}, dest={}", baseDir, destination, e);
}
throw e;
} Prevention
- Verify the base directory exists and is readable before canal startup.
- In containerized deployments, confirm volume mounts are present and paths match config.
- Check file permissions for the JVM process user on all path components.
- Validate paths in health checks to catch missing directories early.
When it happens
Trigger: Calling validateFileName() where either baseDir or basePath+destination cannot be resolved to a canonical path — e.g. baseDir does not exist, a path component is a dangling symlink, or the JVM lacks read/execute permission on a directory in the path.
Common situations: The configured canal data/conf directory does not exist at startup; permissions were changed after deployment; a symlink target was deleted; running in a container where the volume mount path is incorrect or not mounted.
Related errors
- {} has startup , don't repeat start
- {} isn't start , please check
- Invalid destination path
- load extension jar failed!
- dir[{}] can not read/write
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/c13fbdc3dc9792f1.
Report an issue: GitHub.