{"record":{"id":"322a51ec94c80c92","repo":"quarkusio/quarkus","slug":"failure-to-save-the-account","errorCode":null,"errorMessage":"Failure to save the account","messagePattern":"Failure to save the account","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java","lineNumber":168,"sourceCode":"        if (acmeAccount.getKeyAlgorithmName() != null) {\n            json.put(\"key-algorithm\", acmeAccount.getKeyAlgorithmName());\n        }\n        json.put(\"key-size\", acmeAccount.getKeySize());\n        return json;\n    }\n\n    private static void saveAccount(String letsEncryptPath, JsonObject accountJson) {\n        LOGGER.debugf(\"Saving account to %s\", letsEncryptPath);\n\n        // If more than one account must be supported, we can save accounts to unique files in .lets-encrypt/accounts\n        // and require an account alias/id during operations requiring an account\n        java.nio.file.Path accountPath = Paths.get(letsEncryptPath + \"/account.json\");\n        try {\n            AUDIT.debug(\"Writing ACME account to file: \" + accountPath.toString());\n            Files.copy(new ByteArrayInputStream(accountJson.encode().getBytes(StandardCharsets.US_ASCII)), accountPath,\n                    StandardCopyOption.REPLACE_EXISTING);\n        } catch (IOException ex) {\n            throw new RuntimeException(\"Failure to save the account\", ex);\n        }\n    }\n\n    public static void issueCertificate(\n            AcmeClient acmeClient,\n            File letsEncryptPath,\n            boolean staging,\n            String domain,\n            File certChainPemLoc,\n            File privateKeyPemLoc,\n            String acmeServerUrl,\n            String acmeStagingServerUrl) {\n        AcmeAccount acmeAccount = getAccount(letsEncryptPath, acmeServerUrl, acmeStagingServerUrl);\n\n        AUDIT.info(\"Requesting certificate - domain: \" + domain + \", staging: \" + staging + \", server: \"\n                + (acmeServerUrl != null ? acmeServerUrl : \"default\"));\n\n        X509CertificateChainAndSigningKey certChainAndPrivateKey;","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java#L150-L186","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the letsEncrypt directory exists before creating the account: mkdir -p <letsencrypt-dir>","Check write permissions on the directory (and run as a user with access)","Verify the filesystem is not read-only or full (df -h, mount options)","If the error persists, inspect the wrapped cause ('Caused by' IOException) for the exact filesystem failure"],"exampleFix":"// before\nLetsEncryptHelpers.createAccount(acmeClient, new File(\"/nonexistent/letsencrypt\"), termsAgreed, ...); // RuntimeException\n// after\nFile dir = new File(\"/etc/quarkus/letsencrypt\");\ndir.mkdirs();\nLetsEncryptHelpers.createAccount(acmeClient, dir, termsAgreed, ...);","handlingStrategy":"validation","validationCode":"File dir = letsEncryptPath;\nif (!dir.exists() || !dir.isDirectory()) {\n    dir.mkdirs();\n}\nif (!dir.canWrite()) {\n    throw new IllegalStateException(\"Directory not writable: \" + dir);\n}\nLetsEncryptHelpers.createAccount(acmeClient, dir, termsAgreed, email);","typeGuard":null,"tryCatchPattern":"try {\n    LetsEncryptHelpers.createAccount(acmeClient, letsEncryptDir, termsAgreed, email);\n} catch (RuntimeException e) {\n    if (e.getCause() instanceof IOException) {\n        throw new IllegalStateException(\"Cannot write ACME account to \" + letsEncryptDir + \": \" + e.getCause().getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Create the letsencrypt directory (with mkdirs) before account creation","Run the CLI/container as a user with write access to the config directory","Mount persistent writable volumes when running in containers","Monitor disk space on hosts writing certificates"],"tags":["acme","io","filesystem","letsencrypt"],"backgroundTag":"file-write-permission-denied","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}