quarkusio/quarkus · error · RuntimeException

Unable to read the account file, you must create account fir

Error message

Unable to read the account file, you must create account first

What it means

readAccountJson reads <letsEncryptPath>/account.json, which saveAccount writes during account creation. If the file cannot be opened or read (typically because it does not exist), this RuntimeException tells the user they must run account creation first. No underlying exception is chained; the message is the entire diagnostic.

Source

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

            builder.setKey(certificate, privateKey);
        }

        AcmeAccount acmeAccount = builder.build();

        acmeAccount.setContactUrls(new String[] { json.getString("contact-url") });
        acmeAccount.setAccountUrl(json.getString("account-url"));

        return acmeAccount;
    }

    private static JsonObject readAccountJson(File letsEncryptPath) {
        LOGGER.debugf("Reading account information from %s", letsEncryptPath);
        java.nio.file.Path accountPath = Paths.get(letsEncryptPath + "/account.json");
        try (FileInputStream fis = new FileInputStream(accountPath.toString())) {
            return new JsonObject(new String(fis.readAllBytes(), StandardCharsets.US_ASCII));
        } catch (IOException e) {
            throw new RuntimeException("Unable to read the account file, you must create account first");
        }
    }

    private static X509Certificate getCertificate(String encodedCert) {
        try {
            byte[] encodedBytes = Base64.getDecoder().decode(encodedCert);
            return (X509Certificate) CertificateFactory.getInstance("X.509")
                    .generateCertificate(new ByteArrayInputStream(encodedBytes));
        } catch (Exception ex) {
            throw new RuntimeException("Failure to create a certificate", ex);
        }
    }

    private static PrivateKey getPrivateKey(String encodedKey, String keyAlgorithm) {
        try {
            KeyFactory f = KeyFactory.getInstance((keyAlgorithm == null || "RSA".equals(keyAlgorithm) ? "RSA" : "EC"));
            byte[] encodedBytes = Base64.getDecoder().decode(encodedKey);
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedBytes);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Create the ACME account first (run the create-account command / LetsEncryptHelpers.createAccount) so account.json is written
  2. Verify letsEncryptPath points to the directory that actually contains account.json
  3. Check file permissions so the current user can read account.json
  4. If the account was stored on ephemeral storage (container), persist the letsencrypt directory as a volume

Example fix

// before: reading account before it exists
JsonObject json = LetsEncryptHelpers.json(new File("/etc/quarkus/letsencrypt")); // RuntimeException
// after: create the account first
LetsEncryptHelpers.createAccount(acmeClient, new File("/etc/quarkus/letsencrypt"), true, "my@example.com");
JsonObject json = LetsEncryptHelpers.json(new File("/etc/quarkus/letsencrypt"));
Defensive patterns

Strategy: validation

Validate before calling

File dir = letsEncryptPath;
File accountFile = new File(dir, "account.json");
if (!accountFile.isFile() || !accountFile.canRead()) {
    throw new IllegalStateException("ACME account not found at " + accountFile + "; create the account first");
}
JsonObject json = LetsEncryptHelpers.json(dir);

Type guard

boolean hasAcmeAccount(File letsEncryptPath) {
    File f = new File(letsEncryptPath, "account.json");
    return f.isFile() && f.canRead() && f.length() > 0;
}

Try / catch

try {
    JsonObject json = LetsEncryptHelpers.json(letsEncryptPath);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Unable to read the account file")) {
        // account was never created or path is wrong — run account creation flow
        throw new IllegalStateException("No ACME account at " + letsEncryptPath + "/account.json. Run create-account first.", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling the json() method (or any flow calling readAccountJson) before createAccount has ever run, or pointing at a letsEncryptPath directory that contains no account.json.

Common situations: Running 'renew' or account-inspection commands on a fresh machine/checkout without 'create account' first; mistyped or changed letsencrypt directory path; account.json deleted by cleanup scripts or container restarts on ephemeral storage.

Related errors


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