floci-io/floci · error · AwsException

ValidationException

ValidationException

Error message

Invalid certificate: " + e.getMessage()

What it means

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.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/acm/AcmService.java:334

        }

        String storageKey = regionKey(region, cert.extractCertificateId());
        store.delete(storageKey);
        LOG.infov("Deleted certificate: {0}", certificateArn);
    }

    // ============ ImportCertificate ============

    public Certificate importCertificate(String certificatePem, String privateKeyPem, String chainPem,
                                          String existingArn, Map<String, String> tags, String region) {
        logSecurityWarningOnce();
        // Parse and validate certificate
        X509Certificate x509Cert;
        try {
            x509Cert = certificateGenerator.parseCertificate(certificatePem);
            certificateGenerator.validateCertificate(x509Cert);
        } catch (Exception e) {
            throw new AwsException("ValidationException", "Invalid certificate: " + e.getMessage(), 400);
        }

        // Parse and validate private key
        try {
            certificateGenerator.parsePrivateKey(privateKeyPem);
        } catch (Exception e) {
            throw new AwsException("ValidationException", "Invalid private key: " + e.getMessage(), 400);
        }

        if (tags != null) {
            validateTags(tags);
        }

        String certId;
        String arn;

        if (existingArn != null && !existingArn.isEmpty()) {
            // Re-import

View on GitHub (pinned to 62ff490619)

Solutions

  1. Validate the PEM locally first: openssl x509 -in cert.pem -noout -text — if openssl cannot read it, neither can Floci
  2. Ensure the input is a PEM block: -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- with intact Base64 body and newlines
  3. Check you passed the leaf certificate in certificatePem, not the private key or chain (chain goes in certificateChain)
  4. If validateCertificate rejects a parseable cert (e.g. expired), generate a fresh cert or adjust the test fixture

Example fix

// before: DER bytes or mangled PEM
byte[] der = Files.readAllBytes(Path.of("cert.der"));
acm.importCertificate(r -> r.certificatePem(new String(der, StandardCharsets.ISO_8859_1)));

// after: convert to PEM and import
String pem = "-----BEGIN CERTIFICATE-----\n" +
    Base64.getMimeEncoder().encodeToString(der).replaceAll("(.{64})", "$1\n") + "\n-----END CERTIFICATE-----\n";
acm.importCertificate(r -> r.certificatePem(pem));
Defensive patterns

Strategy: validation

Validate before calling

openssl x509 -in cert.pem -noout > /dev/null && echo OK  # gate before import

Type guard

private static boolean isPemCertificate(String pem) {
    return pem != null && pem.contains("-----BEGIN CERTIFICATE-----")
        && pem.contains("-----END CERTIFICATE-----");
}

Try / catch

try {
    acm.importCertificate(r -> r.certificatePem(pem).privateKey(key));
} catch (ValidationException e) {
    if (e.getMessage().contains("Invalid certificate")) { /* re-check PEM fenceposts, regenerate */ }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/3a1a1449f175fc2c. Report an issue: GitHub.