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
- Fetch the existing key with GetPublicKey and send it back unchanged except for Comment.
- To rotate key material, create a new PublicKey and update distribution references, then delete the old key.
- 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
- Always base update payloads on a fresh GetPublicKey response.
- Treat CallerReference/Name/EncodedKey as read-only after creation.
- Rotate keys by create-new + re-reference + delete-old, never by overwriting.
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.