quarkusio/quarkus · error · RuntimeException
Failure to copy certificate pem: + ex.getMessage()
Error message
Failure to copy certificate pem: + ex.getMessage()
What it means
After the certificate chain is obtained, issueCertificate writes the private key and certificate chain as PEM files via writePrivateKeyAndCertificateChainsAsPem. Any exception during this conversion/writing step is wrapped in this RuntimeException (message includes the underlying ex.getMessage(), despite the misplaced quote in the literal). It indicates a local I/O or encoding failure, not an ACME problem.
Source
Thrown at extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java:206
certChainAndPrivateKey = acmeClient.obtainCertificateChain(acmeAccount, staging, domain);
AUDIT.info("Certificate chain obtained successfully - domain: " + domain + ", chain-length: "
+ certChainAndPrivateKey.getCertificateChain().length);
} catch (AcmeException t) {
AUDIT.error("Failed to obtain certificate - domain: " + domain + ", staging: " + staging, t);
throw new RuntimeException("Failed to obtain certificate: " + t.getMessage(), t);
}
LOGGER.info("\uD83D\uDD35 Certificate and private key issued, converting them to PEM files");
AUDIT.info("Writing certificate to: " + certChainPemLoc.getAbsolutePath());
AUDIT.info("Writing private key to: " + privateKeyPemLoc.getAbsolutePath());
try {
LetsEncryptHelpers.writePrivateKeyAndCertificateChainsAsPem(certChainAndPrivateKey.getSigningKey(),
certChainAndPrivateKey.getCertificateChain(), privateKeyPemLoc, certChainPemLoc);
} catch (Exception ex) {
AUDIT.error("Failed to write certificate files - cert: " + certChainPemLoc + ", key: "
+ privateKeyPemLoc, ex);
throw new RuntimeException("Failure to copy certificate pem: " + ex.getMessage(), ex);
}
}
private static AcmeAccount getAccount(File letsEncryptPath, String acmeServerUrl, String acmeStagingServerUrl) {
LOGGER.debugf("Getting account from %s", letsEncryptPath);
// Use defaults if not specified
String serverUrl = acmeServerUrl != null ? acmeServerUrl
: DEFAULT_ACME_URL;
String stagingServerUrl = acmeStagingServerUrl != null ? acmeStagingServerUrl
: DEFAULT_ACME_STAGING_URL;
JsonObject json = readAccountJson(letsEncryptPath);
AcmeAccount.Builder builder = AcmeAccount.builder().setTermsOfServiceAgreed(true)
.setServerUrl(serverUrl)
.setStagingServerUrl(stagingServerUrl);
String keyAlgorithm = json.getString("key-algorithm");View on GitHub (pinned to e1c734241f)
Solutions
- Ensure the parent directories of certChainPemLoc and privateKeyPemLoc exist and are writable
- Check file permissions on the existing pem files (they may be read-only or owned by another user)
- Free disk space if the filesystem is full
- Inspect the wrapped cause in the stack trace for the exact write/encode failure
Example fix
// before
File cert = new File("/missing/dir/cert.pem");
LetsEncryptHelpers.issueCertificate(..., cert, key, ...); // RuntimeException: Failure to copy certificate pem
// after
new File("/missing/dir").mkdirs();
LetsEncryptHelpers.issueCertificate(..., cert, key, ...); Defensive patterns
Strategy: validation
Validate before calling
File cert = certChainPemLoc, key = privateKeyPemLoc;
for (File f : new File[]{cert, key}) {
File parent = f.getAbsoluteFile().getParentFile();
if (parent == null || (!parent.exists() && !parent.mkdirs()) || !parent.canWrite()) {
throw new IllegalStateException("Cannot write to directory: " + parent);
}
if (f.exists() && !f.canWrite()) throw new IllegalStateException("File not writable: " + f);
} Try / catch
try {
LetsEncryptHelpers.issueCertificate(acmeClient, letsEncryptPath, staging, domain, keyLoc, certLoc);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Failure to copy certificate pem:")) {
throw new IllegalStateException("Could not write cert/key to " + certLoc + "/" + keyLoc + ": " + e.getMessage(), e);
}
throw e;
} Prevention
- Create output directories before issuing certificates
- Check write permissions on cert/key target files and directories
- Ensure sufficient disk space before renewals
- Avoid running as a user that cannot overwrite existing pem files
When it happens
Trigger: Calling issueCertificate/renewCertificate when the target certChainPemLoc or privateKeyPemLoc files/directories cannot be written — bad path, missing parent directory, permissions — or the key/certificate cannot be PEM-encoded.
Common situations: Certificate output directory does not exist; the process lacks write permission to the target path; disk full; the existing target file is locked or read-only.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Invalid PEM file: No PEM content found.
- Failed to create output directory for generated sources: %s
- IOException (wrapped)
- Unable to validate the application root for remote-dev path:
- Unable to validate remote-dev path: <file>
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/db288b812641fe2e.
Report an issue: GitHub.