{"record":{"id":"f637fb6b6bd82a18","repo":"floci-io/floci","slug":"validationerror-f637fb","errorCode":"ValidationError","errorMessage":"Updating RoleName requires resource replacement, which is not supported.","messagePattern":"Updating RoleName requires resource replacement, which is not supported\\.","errorType":"validation","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/IamRoleCfnProvisioner.java","lineNumber":58,"sourceCode":"    }\n\n    @Override\n    public Set<String> resourceTypes() {\n        return Set.of(\"AWS::IAM::Role\");\n    }\n\n    @Override\n    public void provision(StackResource r, JsonNode props, ProvisionContext ctx) {\n        String existingRoleName = r.getPhysicalId();\n        String roleName = ctx.resolveOptional(props, \"RoleName\");\n        if (roleName == null || roleName.isBlank()) {\n            roleName = existingRoleName != null && !existingRoleName.isBlank()\n                    ? existingRoleName\n                    : ctx.generatePhysicalName(r.getLogicalId(), 64, false);\n        }\n        final String resolvedRoleName = roleName;\n        if (existingRoleName != null && !existingRoleName.equals(resolvedRoleName)) {\n            throw new AwsException(\"ValidationError\",\n                    \"Updating RoleName requires resource replacement, which is not supported.\", 400);\n        }\n        String assumeDoc = props != null && props.has(\"AssumeRolePolicyDocument\")\n                ? props.get(\"AssumeRolePolicyDocument\").toString()\n                : \"{\\\"Version\\\":\\\"2012-10-17\\\",\\\"Statement\\\":[]}\";\n        String path = ctx.resolveOptional(props, \"Path\");\n        if (path == null) {\n            path = \"/\";\n        }\n        String description = ctx.resolveOptional(props, \"Description\");\n        List<String> managedPolicyArns = ctx.resolveStringList(props, \"ManagedPolicyArns\");\n\n        IamRole role;\n        boolean createdRole = false;\n        // Set only on the adoption path, to the role's trust policy (and verified RoleId) as they\n        // were before this attempt touched them. Lets a later failure (e.g. bad ManagedPolicyArns)\n        // restore the trust policy below, so a rolled-back update doesn't leave it changed despite\n        // UPDATE_ROLLBACK_COMPLETE - and restore it onto the *same verified role*, not onto a","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/IamRoleCfnProvisioner.java#L40-L76","documentation":"ValidationError from the AWS::IAM::Role provisioner when an update resolves a different RoleName than the one recorded at create time. RoleName is a replacement property in AWS and the emulator does not model replacement here, so a mismatch is rejected instead of creating a second role.","triggerScenarios":"UpdateStack where the template's RoleName differs from the stack resource's physical id — adding a RoleName to a role that was originally created unnamed (generated name), or editing the declared name.","commonSituations":"Templates versioned over time that introduce or rename RoleName; environments where a role first deployed without an explicit name is later tightened to carry one.","solutions":["Keep RoleName identical across updates, or omit it in every version of the template.","If a rename is required, treat it as replacement: delete and recreate the stack or move the role to a new logical id.","Note the same asymmetry as other named resources: once created unnamed, the generated name is sticky and adding a declared name always fails."],"exampleFix":"# before (v1 had no RoleName, v2 adds one)\nType: AWS::IAM::Role\nProperties:\n  RoleName: app-role   # != generated physical id\n\n# after (keep consistent across versions)\nType: AWS::IAM::Role\nProperties:\n  # no RoleName in any version; or set it in v1 from the start\n  AssumeRolePolicyDocument: ...","handlingStrategy":"validation","validationCode":"String declared = template.stringAt(\"Resources/Role/Properties/RoleName\");\nString recorded = describeStackResource(stack, \"Role\").physicalResourceId();\nif (declared != null && !declared.equals(recorded)) {\n    throw new IllegalStateException(\"RoleName change requires stack recreation\");\n}","typeGuard":null,"tryCatchPattern":"catch ValidationError \"Updating RoleName requires resource replacement\": revert RoleName in the template, or recreate (new logical id / new stack); the update itself can never succeed.","preventionTips":["Set RoleName once at first deploy or never set it","Never add a RoleName to a resource that was previously created unnamed","Model renames as explicit delete+create in deployment pipelines"],"tags":["cloudformation","iam","role","replacement"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}