alibaba/spring-cloud-alibaba · error · IOException

File '{}' cannot be read

Error message

File '{}' cannot be read

What it means

Thrown by FileUtils.openInputStream when the file exists and is not a directory, but the current process lacks read permission (file.canRead() returns false). This provides a clearer error message than the generic exception from new FileInputStream(file), which may throw a less descriptive AccessDeniedException on some platforms.

Source

Thrown at spring-cloud-alibaba-starters/spring-cloud-alibaba-commons/src/main/java/com/alibaba/cloud/commons/io/FileUtils.java:60

	 * exception will have been thrown.
	 * <p>
	 * An exception is thrown if the file does not exist. An exception is thrown if the
	 * file object exists but is a directory. An exception is thrown if the file exists
	 * but cannot be read.
	 * @param file the file to open for input, must not be {@code null}
	 * @return a new {@link java.io.FileInputStream} for the specified file
	 * @throws java.io.FileNotFoundException if the file does not exist
	 * @throws IOException if the file object is a directory
	 * @throws IOException if the file cannot be read
	 * @since 1.3
	 */
	public static FileInputStream openInputStream(final File file) throws IOException {
		if (file.exists()) {
			if (file.isDirectory()) {
				throw new IOException("File '" + file + "' exists but is a directory");
			}
			if (!file.canRead()) {
				throw new IOException("File '" + file + "' cannot be read");
			}
		}
		else {
			throw new FileNotFoundException("File '" + file + "' does not exist");
		}
		return new FileInputStream(file);
	}

	// -----------------------------------------------------------------------
	/**
	 * Reads the contents of a file into a String. The file is always closed.
	 * @param file the file to read, must not be {@code null}
	 * @param encoding the encoding to use, {@code null} means platform default
	 * @return the file contents, never {@code null}
	 * @throws IOException in case of an I/O error
	 */
	public static String readFileToString(final File file, final Charset encoding)
			throws IOException {

View on GitHub (pinned to 115d590110)

Solutions

  1. Grant read permission to the JVM process user: chmod +r <file> or chmod 644 <file>.
  2. If running in a container, ensure the Dockerfile or init script sets correct file ownership and permissions (chown / chmod).

Example fix

# before (file owned by root, app runs as appuser)
# ls -l config.yml -> -rw------- root root

# after (fix permissions)
chmod 644 config.yml
# or change ownership
chown appuser:appuser config.yml
Defensive patterns

Strategy: validation

Validate before calling

File file = new File(path);
if (!file.canRead()) {
    throw new IllegalStateException(
        "Cannot read file: " + file.getAbsolutePath()
        + " — check permissions for user: " + System.getProperty("user.name"));
}
FileInputStream fis = FileUtils.openInputStream(file);

Type guard

import java.io.File;

boolean isReadableFile(File file) {
    return file != null && file.exists() && file.isFile() && file.canRead();
}

Try / catch

try {
    InputStream in = FileUtils.openInputStream(file);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().contains("cannot be read")) {
        log.error("Permission denied reading {} — current user: {}",
            file, System.getProperty("user.name"));
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling FileUtils.openInputStream(file) where the file exists, is a regular file, but the OS file permissions deny read access to the JVM process. Common in containerized deployments where file ownership or mode bits differ from the running user.

Common situations: 1) Docker/Kubernetes container running as non-root user while files are owned by root with mode 600. 2) File extracted from an archive with restrictive permissions. 3) SELinux or AppArmor denying read access. 4) NFS mount with mapping that strips read permission.

Related errors


AI-assisted analysis of alibaba/spring-cloud-alibaba@115d590110 (2026-08-14). Data as JSON: /api/errors/0d83c02347b4beb7. Report an issue: GitHub.