floci-io/floci · error · AwsException

CannotChangeImmutablePublicKeyFields

CannotChangeImmutablePublicKeyFields

Error message

The caller reference, name, and encoded public key cannot be changed.

What it means

CloudFrontService.updatePublicKey throws CannotChangeImmutablePublicKeyFields (HTTP 400) when an update attempts to change CallerReference, Name, or EncodedKey relative to the stored key. In CloudFront only the Comment field is mutable after creation; identity-bearing fields are immutable, and the emulator enforces this with a strict Objects.equals comparison before applying the update.

Source

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

                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);
        if (!existing.getEtag().equals(ifMatch)) {
            throw new AwsException(
                    "PreconditionFailed",
                    "The precondition in one or more request-header fields evaluated to false.",
                    412);
        }
        validatePublicKey(updated);
        if (!Objects.equals(
                    existing.getCallerReference(),
                    updated.getCallerReference())
                || !Objects.equals(existing.getName(), updated.getName())
                || !Objects.equals(
                    existing.getEncodedKey(), updated.getEncodedKey())) {
            throw new AwsException(
                    "CannotChangeImmutablePublicKeyFields",
                    "The caller reference, name, and encoded public key cannot be changed.",
                    400);
        }
        updated.setId(id);
        updated.setCreatedTime(existing.getCreatedTime());
        updated.setEtag(UUID.randomUUID().toString());
        publicKeyStore.put(id, updated);
        return updated;
    }

    public synchronized void deletePublicKey(String id, String ifMatch) {
        PublicKey existing = getPublicKey(id);
        if (!existing.getEtag().equals(ifMatch)) {
            throw new AwsException(
                    "PreconditionFailed",
                    "The precondition in one or more request-header fields evaluated to false.",
                    412);

View on GitHub (pinned to 62ff490619)

Solutions

  1. Fetch the existing key with GetPublicKey and send it back unchanged except for Comment.
  2. To rotate key material, create a new PublicKey and update distribution references, then delete the old key.
  3. Diff the fetched key against your payload before submitting and fail fast client-side if identity fields differ.

Example fix

// before
PublicKey update = new PublicKey();
update.setName("new-name");       // immutable!
update.setEncodedKey(newPem);     // immutable!
update.setCallerReference(uuid()); // immutable!
updateKey(id, etag, update); // 400

// after
PublicKey update = getPublicKey(id);
update.setComment("rotated 2026-08"); // only mutable field
updateKey(id, etag, update);
Defensive patterns

Strategy: validation

Validate before calling

void assertOnlyCommentChanged(PublicKey existing, PublicKey updated) {
    if (!Objects.equals(existing.getCallerReference(), updated.getCallerReference())
            || !Objects.equals(existing.getName(), updated.getName())
            || !Objects.equals(existing.getEncodedKey(), updated.getEncodedKey())) {
        throw new IllegalArgumentException("Only Comment may change on UpdatePublicKey");
    }
}

Try / catch

try {
    client.updatePublicKey(r -> r.id(id).ifMatch(etag).publicKeyConfig(cfg));
} catch (CannotChangeImmutablePublicKeyFields e) {
    PublicKey current = client.getPublicKey(r -> r.id(id)).publicKeyConfig();
    // rebuild from current, change only comment, then retry with fresh etag
}

Prevention

When it happens

Trigger: UpdatePublicKey that sends a different Name, a re-encoded key body, or a regenerated CallerReference — commonly because the client rebuilds the whole PublicKey object from scratch instead of echoing the existing values and only editing Comment.

Common situations: Rotating a key by trying to overwrite EncodedKey in place (AWS requires create-new + switch references + delete-old); copying a config object from another key as the update base; form UIs that resubmit every field.

Related errors


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