{"record":{"id":"95e966e46021cef2","repo":"floci-io/floci","slug":"cannotchangeimmutablepublickeyfields","errorCode":"CannotChangeImmutablePublicKeyFields","errorMessage":"The caller reference, name, and encoded public key cannot be changed.","messagePattern":"The caller reference, name, and encoded public key cannot be changed\\.","errorType":"exception","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/cloudfront/CloudFrontService.java","lineNumber":962,"sourceCode":"                new AwsException(\"NoSuchPublicKey\", \"The specified public key does not exist.\", 404));\n    }\n\n    public synchronized PublicKey updatePublicKey(String id, String ifMatch, PublicKey updated) {\n        PublicKey existing = getPublicKey(id);\n        if (!existing.getEtag().equals(ifMatch)) {\n            throw new AwsException(\n                    \"PreconditionFailed\",\n                    \"The precondition in one or more request-header fields evaluated to false.\",\n                    412);\n        }\n        validatePublicKey(updated);\n        if (!Objects.equals(\n                    existing.getCallerReference(),\n                    updated.getCallerReference())\n                || !Objects.equals(existing.getName(), updated.getName())\n                || !Objects.equals(\n                    existing.getEncodedKey(), updated.getEncodedKey())) {\n            throw new AwsException(\n                    \"CannotChangeImmutablePublicKeyFields\",\n                    \"The caller reference, name, and encoded public key cannot be changed.\",\n                    400);\n        }\n        updated.setId(id);\n        updated.setCreatedTime(existing.getCreatedTime());\n        updated.setEtag(UUID.randomUUID().toString());\n        publicKeyStore.put(id, updated);\n        return updated;\n    }\n\n    public synchronized void deletePublicKey(String id, String ifMatch) {\n        PublicKey existing = getPublicKey(id);\n        if (!existing.getEtag().equals(ifMatch)) {\n            throw new AwsException(\n                    \"PreconditionFailed\",\n                    \"The precondition in one or more request-header fields evaluated to false.\",\n                    412);","sourceCodeStart":944,"sourceCodeEnd":980,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/cloudfront/CloudFrontService.java#L944-L980","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nPublicKey update = new PublicKey();\nupdate.setName(\"new-name\");       // immutable!\nupdate.setEncodedKey(newPem);     // immutable!\nupdate.setCallerReference(uuid()); // immutable!\nupdateKey(id, etag, update); // 400\n\n// after\nPublicKey update = getPublicKey(id);\nupdate.setComment(\"rotated 2026-08\"); // only mutable field\nupdateKey(id, etag, update);","handlingStrategy":"validation","validationCode":"void assertOnlyCommentChanged(PublicKey existing, PublicKey updated) {\n    if (!Objects.equals(existing.getCallerReference(), updated.getCallerReference())\n            || !Objects.equals(existing.getName(), updated.getName())\n            || !Objects.equals(existing.getEncodedKey(), updated.getEncodedKey())) {\n        throw new IllegalArgumentException(\"Only Comment may change on UpdatePublicKey\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    client.updatePublicKey(r -> r.id(id).ifMatch(etag).publicKeyConfig(cfg));\n} catch (CannotChangeImmutablePublicKeyFields e) {\n    PublicKey current = client.getPublicKey(r -> r.id(id)).publicKeyConfig();\n    // rebuild from current, change only comment, then retry with fresh etag\n}","preventionTips":["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."],"tags":["cloudfront","public-key","immutable-fields","validation","aws-emulator"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}