grpc/grpc-java · error · GeneralSecurityException

Files were unmodified before their initial update. Probably

Error message

Files were unmodified before their initial update. Probably a bug.

What it means

AdvancedTlsX509KeyManager.updateIdentityCredentials (scheduling variant) performs an initial synchronous read of the cert/key files via readAndUpdate; if that initial update reports failure it throws GeneralSecurityException, since there is no usable identity material to install and periodic refreshing cannot proceed meaningfully.

Source

Thrown at util/src/main/java/io/grpc/util/AdvancedTlsX509KeyManager.java:173

   * updated. You must close the returned Closeable before calling this method again or other update
   * methods ({@link AdvancedTlsX509KeyManager#updateIdentityCredentials}, {@link
   * AdvancedTlsX509KeyManager#updateIdentityCredentials(File, File)}).
   * Before scheduling the task, the method synchronously executes {@code  readAndUpdate} once. The
   * minimum refresh period of 1 minute is enforced.
   *
   * @param certFile  the file on disk holding the certificate chain
   * @param keyFile  the file on disk holding the private key
   * @param period the period between successive read-and-update executions
   * @param unit the time unit of the initialDelay and period parameters
   * @param executor the executor service we use to read and update the credentials
   * @return an object that caller should close when the file refreshes are not needed
   */
  public Closeable updateIdentityCredentials(File certFile, File keyFile,
      long period, TimeUnit unit, ScheduledExecutorService executor) throws IOException,
      GeneralSecurityException {
    UpdateResult newResult = readAndUpdate(certFile, keyFile, 0, 0);
    if (!newResult.success) {
      throw new GeneralSecurityException(
          "Files were unmodified before their initial update. Probably a bug.");
    }
    if (checkNotNull(unit, "unit").toMinutes(period) < MINIMUM_REFRESH_PERIOD_IN_MINUTES) {
      log.log(Level.FINE,
          "Provided refresh period of {0} {1} is too small. Default value of {2} minute(s) "
          + "will be used.", new Object[] {period, unit.name(), MINIMUM_REFRESH_PERIOD_IN_MINUTES});
      period = MINIMUM_REFRESH_PERIOD_IN_MINUTES;
      unit = TimeUnit.MINUTES;
    }
    final ScheduledFuture<?> future =
        checkNotNull(executor, "executor").scheduleWithFixedDelay(
            new LoadFilePathExecution(certFile, keyFile), period, period, unit);
    return () -> future.cancel(false);
  }

  /**
   * Updates certificate chains and the private key from the local file paths.
   *

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Verify certFile and keyFile exist, are readable, and contain valid matching PEM material before calling
  2. Check the private key corresponds to the certificate (matching public keys)
  3. Ensure files are fully written/mounted before credential setup (no partial secret mounts)
  4. Catch GeneralSecurityException/IOException at startup and fail fast with a clear log message

Example fix

// before
km.updateIdentityCredentials(cert, key, 1, TimeUnit.HOURS, executor); // throws if files bad
// after
if (cert.exists() && key.exists()) {
  km.updateIdentityCredentials(cert, key, 1, TimeUnit.HOURS, executor);
} else { log.severe("missing key material"); }
Defensive patterns

Strategy: validation

Validate before calling

if (!certFile.canRead() || !keyFile.canRead() || certFile.length() == 0 || keyFile.length() == 0) { throw new IOException("Cert/key files missing or empty"); }

Try / catch

try { km.updateIdentityCredentials(cert, key, period, unit, executor); } catch (GeneralSecurityException | IOException e) { /* fail fast with config diagnostics */ }

Prevention

When it happens

Trigger: Calling updateIdentityCredentials(certFile, keyFile, period, unit, executor) where readAndUpdate fails on the first attempt: missing files, unreadable paths, invalid/corrupt PEM or PKCS#12 content, or wrong password/format.

Common situations: Wrong file paths in deployment config; secrets mounted late or empty; certificate format mismatch (e.g. DER vs PEM); key not matching certificate.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/89a2d4930acff57d. Report an issue: GitHub.