quarkusio/quarkus · error · RuntimeException

Failure to save the account

Error message

Failure to save the account

What it means

saveAccount persists the ACME account JSON to <letsEncryptPath>/account.json via Files.copy with REPLACE_EXISTING. Any IOException while writing (bad directory, permissions, disk full) is wrapped in this RuntimeException. Without the account file, later certificate operations cannot authenticate.

Source

Thrown at extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java:168

        if (acmeAccount.getKeyAlgorithmName() != null) {
            json.put("key-algorithm", acmeAccount.getKeyAlgorithmName());
        }
        json.put("key-size", acmeAccount.getKeySize());
        return json;
    }

    private static void saveAccount(String letsEncryptPath, JsonObject accountJson) {
        LOGGER.debugf("Saving account to %s", letsEncryptPath);

        // If more than one account must be supported, we can save accounts to unique files in .lets-encrypt/accounts
        // and require an account alias/id during operations requiring an account
        java.nio.file.Path accountPath = Paths.get(letsEncryptPath + "/account.json");
        try {
            AUDIT.debug("Writing ACME account to file: " + accountPath.toString());
            Files.copy(new ByteArrayInputStream(accountJson.encode().getBytes(StandardCharsets.US_ASCII)), accountPath,
                    StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException ex) {
            throw new RuntimeException("Failure to save the account", ex);
        }
    }

    public static void issueCertificate(
            AcmeClient acmeClient,
            File letsEncryptPath,
            boolean staging,
            String domain,
            File certChainPemLoc,
            File privateKeyPemLoc,
            String acmeServerUrl,
            String acmeStagingServerUrl) {
        AcmeAccount acmeAccount = getAccount(letsEncryptPath, acmeServerUrl, acmeStagingServerUrl);

        AUDIT.info("Requesting certificate - domain: " + domain + ", staging: " + staging + ", server: "
                + (acmeServerUrl != null ? acmeServerUrl : "default"));

        X509CertificateChainAndSigningKey certChainAndPrivateKey;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Ensure the letsEncrypt directory exists before creating the account: mkdir -p <letsencrypt-dir>
  2. Check write permissions on the directory (and run as a user with access)
  3. Verify the filesystem is not read-only or full (df -h, mount options)
  4. If the error persists, inspect the wrapped cause ('Caused by' IOException) for the exact filesystem failure

Example fix

// before
LetsEncryptHelpers.createAccount(acmeClient, new File("/nonexistent/letsencrypt"), termsAgreed, ...); // RuntimeException
// after
File dir = new File("/etc/quarkus/letsencrypt");
dir.mkdirs();
LetsEncryptHelpers.createAccount(acmeClient, dir, termsAgreed, ...);
Defensive patterns

Strategy: validation

Validate before calling

File dir = letsEncryptPath;
if (!dir.exists() || !dir.isDirectory()) {
    dir.mkdirs();
}
if (!dir.canWrite()) {
    throw new IllegalStateException("Directory not writable: " + dir);
}
LetsEncryptHelpers.createAccount(acmeClient, dir, termsAgreed, email);

Try / catch

try {
    LetsEncryptHelpers.createAccount(acmeClient, letsEncryptDir, termsAgreed, email);
} catch (RuntimeException e) {
    if (e.getCause() instanceof IOException) {
        throw new IllegalStateException("Cannot write ACME account to " + letsEncryptDir + ": " + e.getCause().getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling createAccount (which calls saveAccount) when letsEncryptPath does not exist or is not writable — e.g. directory missing, read-only filesystem, or insufficient file permissions.

Common situations: Running the CLI as a user without write access to the config directory; letsencrypt directory not created beforehand; running in a container with a read-only filesystem; disk full on the host.

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.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/322a51ec94c80c92. Report an issue: GitHub.