{"record":{"id":"89a2d4930acff57d","repo":"grpc/grpc-java","slug":"files-were-unmodified-before-their-initial-update","errorCode":null,"errorMessage":"Files were unmodified before their initial update. Probably a bug.","messagePattern":"Files were unmodified before their initial update\\. Probably a bug\\.","errorType":"exception","errorClass":"GeneralSecurityException","httpStatus":null,"severity":"error","filePath":"util/src/main/java/io/grpc/util/AdvancedTlsX509KeyManager.java","lineNumber":173,"sourceCode":"   * updated. You must close the returned Closeable before calling this method again or other update\n   * methods ({@link AdvancedTlsX509KeyManager#updateIdentityCredentials}, {@link\n   * AdvancedTlsX509KeyManager#updateIdentityCredentials(File, File)}).\n   * Before scheduling the task, the method synchronously executes {@code  readAndUpdate} once. The\n   * minimum refresh period of 1 minute is enforced.\n   *\n   * @param certFile  the file on disk holding the certificate chain\n   * @param keyFile  the file on disk holding the private key\n   * @param period the period between successive read-and-update executions\n   * @param unit the time unit of the initialDelay and period parameters\n   * @param executor the executor service we use to read and update the credentials\n   * @return an object that caller should close when the file refreshes are not needed\n   */\n  public Closeable updateIdentityCredentials(File certFile, File keyFile,\n      long period, TimeUnit unit, ScheduledExecutorService executor) throws IOException,\n      GeneralSecurityException {\n    UpdateResult newResult = readAndUpdate(certFile, keyFile, 0, 0);\n    if (!newResult.success) {\n      throw new GeneralSecurityException(\n          \"Files were unmodified before their initial update. Probably a bug.\");\n    }\n    if (checkNotNull(unit, \"unit\").toMinutes(period) < MINIMUM_REFRESH_PERIOD_IN_MINUTES) {\n      log.log(Level.FINE,\n          \"Provided refresh period of {0} {1} is too small. Default value of {2} minute(s) \"\n          + \"will be used.\", new Object[] {period, unit.name(), MINIMUM_REFRESH_PERIOD_IN_MINUTES});\n      period = MINIMUM_REFRESH_PERIOD_IN_MINUTES;\n      unit = TimeUnit.MINUTES;\n    }\n    final ScheduledFuture<?> future =\n        checkNotNull(executor, \"executor\").scheduleWithFixedDelay(\n            new LoadFilePathExecution(certFile, keyFile), period, period, unit);\n    return () -> future.cancel(false);\n  }\n\n  /**\n   * Updates certificate chains and the private key from the local file paths.\n   *","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/util/src/main/java/io/grpc/util/AdvancedTlsX509KeyManager.java#L155-L191","documentation":"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.","triggerScenarios":"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.","commonSituations":"Wrong file paths in deployment config; secrets mounted late or empty; certificate format mismatch (e.g. DER vs PEM); key not matching certificate.","solutions":["Verify certFile and keyFile exist, are readable, and contain valid matching PEM material before calling","Check the private key corresponds to the certificate (matching public keys)","Ensure files are fully written/mounted before credential setup (no partial secret mounts)","Catch GeneralSecurityException/IOException at startup and fail fast with a clear log message"],"exampleFix":"// before\nkm.updateIdentityCredentials(cert, key, 1, TimeUnit.HOURS, executor); // throws if files bad\n// after\nif (cert.exists() && key.exists()) {\n  km.updateIdentityCredentials(cert, key, 1, TimeUnit.HOURS, executor);\n} else { log.severe(\"missing key material\"); }","handlingStrategy":"validation","validationCode":"if (!certFile.canRead() || !keyFile.canRead() || certFile.length() == 0 || keyFile.length() == 0) { throw new IOException(\"Cert/key files missing or empty\"); }","typeGuard":null,"tryCatchPattern":"try { km.updateIdentityCredentials(cert, key, period, unit, executor); } catch (GeneralSecurityException | IOException e) { /* fail fast with config diagnostics */ }","preventionTips":["Pre-validate cert/key files exist and parse","Ensure secrets are mounted before startup","Check key matches certificate"],"tags":["grpc","tls","security","file-read"],"backgroundTag":"file-read-failed","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}