{"record":{"id":"3a1a1449f175fc2c","repo":"floci-io/floci","slug":"validationexception-3a1a14","errorCode":"ValidationException","errorMessage":"Invalid certificate: \" + e.getMessage()","messagePattern":"Invalid certificate: \" \\+ e\\.getMessage\\(\\)","errorType":"http","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/acm/AcmService.java","lineNumber":334,"sourceCode":"        }\n\n        String storageKey = regionKey(region, cert.extractCertificateId());\n        store.delete(storageKey);\n        LOG.infov(\"Deleted certificate: {0}\", certificateArn);\n    }\n\n    // ============ ImportCertificate ============\n\n    public Certificate importCertificate(String certificatePem, String privateKeyPem, String chainPem,\n                                          String existingArn, Map<String, String> tags, String region) {\n        logSecurityWarningOnce();\n        // Parse and validate certificate\n        X509Certificate x509Cert;\n        try {\n            x509Cert = certificateGenerator.parseCertificate(certificatePem);\n            certificateGenerator.validateCertificate(x509Cert);\n        } catch (Exception e) {\n            throw new AwsException(\"ValidationException\", \"Invalid certificate: \" + e.getMessage(), 400);\n        }\n\n        // Parse and validate private key\n        try {\n            certificateGenerator.parsePrivateKey(privateKeyPem);\n        } catch (Exception e) {\n            throw new AwsException(\"ValidationException\", \"Invalid private key: \" + e.getMessage(), 400);\n        }\n\n        if (tags != null) {\n            validateTags(tags);\n        }\n\n        String certId;\n        String arn;\n\n        if (existingArn != null && !existingArn.isEmpty()) {\n            // Re-import","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/acm/AcmService.java#L316-L352","documentation":"ACM ValidationException (HTTP 400) thrown by AcmService.importCertificate when the PEM certificate body cannot be parsed (certificateGenerator.parseCertificate) or fails validation (validateCertificate). The underlying parser message is appended, so the exact JCA failure (e.g. 'could not be parsed', expiry) is visible.","triggerScenarios":"acm.importCertificate with a CertificatePem that is not a valid PEM X.509 block: wrong header/footer, Windows line endings mangled through a lossy channel, a chain pasted into the certificate field, Base64 (DER) bytes instead of PEM, or a certificate rejected by validateCertificate (e.g. expired).","commonSituations":"Copy-pasting certs from docs/secrets losing newlines; passing the private key or CA bundle in the certificate parameter; loading files with Files.readString on binary DER; environment differences where a trailing newline is stripped.","solutions":["Validate the PEM locally first: openssl x509 -in cert.pem -noout -text — if openssl cannot read it, neither can Floci","Ensure the input is a PEM block: -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- with intact Base64 body and newlines","Check you passed the leaf certificate in certificatePem, not the private key or chain (chain goes in certificateChain)","If validateCertificate rejects a parseable cert (e.g. expired), generate a fresh cert or adjust the test fixture"],"exampleFix":"// before: DER bytes or mangled PEM\nbyte[] der = Files.readAllBytes(Path.of(\"cert.der\"));\nacm.importCertificate(r -> r.certificatePem(new String(der, StandardCharsets.ISO_8859_1)));\n\n// after: convert to PEM and import\nString pem = \"-----BEGIN CERTIFICATE-----\\n\" +\n    Base64.getMimeEncoder().encodeToString(der).replaceAll(\"(.{64})\", \"$1\\n\") + \"\\n-----END CERTIFICATE-----\\n\";\nacm.importCertificate(r -> r.certificatePem(pem));","handlingStrategy":"validation","validationCode":"openssl x509 -in cert.pem -noout > /dev/null && echo OK  # gate before import","typeGuard":"private static boolean isPemCertificate(String pem) {\n    return pem != null && pem.contains(\"-----BEGIN CERTIFICATE-----\")\n        && pem.contains(\"-----END CERTIFICATE-----\");\n}","tryCatchPattern":"try {\n    acm.importCertificate(r -> r.certificatePem(pem).privateKey(key));\n} catch (ValidationException e) {\n    if (e.getMessage().contains(\"Invalid certificate\")) { /* re-check PEM fenceposts, regenerate */ }\n}","preventionTips":["Always gate PEM inputs with openssl x509/pkey -noout checks before importing","Keep cert, key, and chain in clearly named files so they never get swapped","Move PEMs through systems as single-line Base64 and re-wrap locally to protect newlines"],"tags":["acm","import-certificate","pem","x509","validation","aws"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}