floci-io/floci · error · AwsException

PublicKeyAlreadyExists

PublicKeyAlreadyExists

Error message

A public key with this caller reference already exists.

What it means

CloudFrontService.createPublicKey throws PublicKeyAlreadyExists (HTTP 409) when any stored public key already carries the same CallerReference. CallerReference is CloudFront's idempotency token for key creation, and this emulator treats a reused token as a conflict rather than returning the original resource.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/cloudfront/CloudFrontService.java:930

        copy.setConfig(primary.getConfig());
        if (copy.getConfig() != null) {
            copy.getConfig().setCallerReference(callerReference);
            copy.getConfig().setStaging(true);
        }
        return createDistribution(copy, tags);
    }

    // ── Public Keys ───────────────────────────────────────────────────────────

    public synchronized PublicKey createPublicKey(PublicKey key) {
        validatePublicKey(key);
        boolean duplicateCallerReference =
                publicKeyStore.scan(existing -> true).stream()
                        .anyMatch(existing -> Objects.equals(
                                existing.getCallerReference(),
                                key.getCallerReference()));
        if (duplicateCallerReference) {
            throw new AwsException(
                    "PublicKeyAlreadyExists",
                    "A public key with this caller reference already exists.",
                    409);
        }
        key.setId(UUID.randomUUID().toString());
        key.setCreatedTime(Instant.now());
        key.setEtag(UUID.randomUUID().toString());
        publicKeyStore.put(key.getId(), key);
        return key;
    }

    public PublicKey getPublicKey(String id) {
        return publicKeyStore.get(id).orElseThrow(() ->
                new AwsException("NoSuchPublicKey", "The specified public key does not exist.", 404));
    }

    public synchronized PublicKey updatePublicKey(String id, String ifMatch, PublicKey updated) {
        PublicKey existing = getPublicKey(id);

View on GitHub (pinned to 62ff490619)

Solutions

  1. Generate a fresh unique CallerReference (UUID) for every CreatePublicKey call.
  2. If this is a retry after an uncertain failure, first check ListPublicKeys/GetPublicKey for the earlier creation before re-submitting.
  3. Parameterize fixtures so each test run mints its own token instead of reusing a constant.

Example fix

// before
key.setCallerReference("fixed-token");
createPublicKey(key); // ok
createPublicKey(key); // 409 PublicKeyAlreadyExists

// after
key.setCallerReference(UUID.randomUUID().toString());
createPublicKey(key);
Defensive patterns

Strategy: validation

Validate before calling

boolean callerReferenceInUse(CloudFrontClient client, String ref) {
    return client.listPublicKeys(r -> r.build()).publicKeyList().items().stream()
            .anyMatch(k -> ref.equals(k.callerReference()));
}

// before create:
if (callerReferenceInUse(client, ref)) throw new IllegalStateException("caller reference already used");

Try / catch

try {
    return client.createPublicKey(r -> r.publicKeyConfig(cfg));
} catch (PublicKeyAlreadyExists e) {
    // this caller reference already created a key; look it up and reuse it
    return client.listPublicKeys(r -> r.build()).publicKeyList().items().stream()
            .filter(k -> ref.equals(k.callerReference())).findFirst()
            .orElseThrow(() -> e);
}

Prevention

When it happens

Trigger: CreatePublicKey twice with the same CallerReference string — e.g. a fixed token like "key-1" hardcoded in config, or a retry after a timeout that resends the same token after the first create actually succeeded.

Common situations: Hardcoded CallerReferences in templates or test fixtures; retries of flaky requests where the first attempt succeeded; copy-pasted JSON payloads between environments pointed at the same emulator instance.

Related errors


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