grpc/grpc-java · error · IOException
Certificate file not found or not readable
Error message
Certificate file not found or not readable: ${trustCertFile.getAbsolutePath()} What it means
readAndUpdate calls File.lastModified() on the trust certificate file; a return value of 0 means the file does not exist or cannot be read (or the filesystem cannot report its mtime). The library surfaces this as an IOException naming the offending path so the caller knows which certificate file is unavailable.
Solutions
- Verify the file exists at the exact absolute path (File.exists() / canRead()) before configuring the trust manager
- Use an absolute path or confirm the process working directory matches the relative path assumption
- Check filesystem permissions for the user running the process (and mount the cert file in containers)
- If the file is rotated, do so atomically (temp file + rename) and ensure it always exists
- If the file exists but lastModified() is still 0, move it to a local filesystem that reports mtimes
Example fix
// before
File cert = new File("trust.pem"); // resolved against unknown cwd
manager.updateTrustCredentials(cert);
// after
File cert = new File("/etc/app/tls/trust.pem");
if (!cert.exists() || !cert.canRead()) {
throw new FileNotFoundException("Trust cert missing/unreadable: " + cert.getAbsolutePath());
}
manager.updateTrustCredentials(cert); Defensive patterns
Strategy: validation
Validate before calling
File cert = new File(trustCertPath);
if (!cert.isFile() || !cert.canRead() || cert.lastModified() == 0) {
throw new FileNotFoundException("Trust cert not found/readable: " + cert.getAbsolutePath());
} Try / catch
try {
manager.updateTrustCredentials(certFile);
} catch (IOException e) {
if (e.getMessage().startsWith("Certificate file not found or not readable")) {
throw new ConfigurationException("Fix trust cert path/permissions: " + e.getMessage(), e);
}
throw e;
} Prevention
- Use absolute paths for certificate files; never rely on process cwd
- Check exists()/canRead()/lastModified() before configuring
- Mount certificate files into containers and verify with the runtime user's permissions
- Rotate files atomically (write temp + rename) so the file always exists
- Avoid storing trust files on mounts that do not report modification times
When it happens
Trigger: Any call path through readAndUpdate — one-shot updateTrustCredentials(File), scheduled updateTrustCredentials(File, long, TimeUnit, ScheduledExecutorService), or the periodic refresh task — when trustCertFile.lastModified() returns 0 because the path is missing, unreadable, or on a filesystem that does not expose modification times.
Common situations: Typo'd or relative path resolved against the wrong working directory; certificate file deleted before first use; container images built without the cert file mounted; permissions tightened after deployment; files on network mounts returning mtime 0.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Files were unmodified before their initial update. Probably…
- A key manager is required
- ca_certificate_provider_instance name
- ca_certificate_provider_instance or system_root_certs is…
- Can't set TLS settings for ALTS
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/ece6a663765ce94a.
Report an issue: GitHub.
Appendix: source
Thrown at util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java:343
log.log(Level.SEVERE, String.format("Failed refreshing trust CAs from file. Using "
+ "previous CAs (file lastModified = %s)", file.lastModified()), e);
}
}
}
/**
* Reads the trust certificates specified in the path location, and updates the key store if the
* modified time has changed since last read.
*
* @param trustCertFile the file on disk holding the trust certificates
* @param oldTime the time when the trust file is modified during last execution
* @return oldTime if failed or the modified time is not changed, otherwise the new modified time
*/
private long readAndUpdate(File trustCertFile, long oldTime)
throws IOException, GeneralSecurityException {
long newTime = checkNotNull(trustCertFile, "trustCertFile").lastModified();
if (newTime == 0) {
throw new IOException(
"Certificate file not found or not readable: " + trustCertFile.getAbsolutePath());
}
if (newTime == oldTime) {
return oldTime;
}
FileInputStream inputStream = new FileInputStream(trustCertFile);
try {
X509Certificate[] certificates = CertificateUtils.getX509Certificates(inputStream);
updateTrustCredentials(certificates);
return newTime;
} finally {
inputStream.close();
}
}
// Mainly used to avoid throwing IO Exceptions in java.io.Closeable.
public interface Closeable extends java.io.Closeable {
@OverrideView on GitHub (pinned to 64daddc1f3)