floci-io/floci · error · AwsException
ValidationError
ValidationError
Error message
Updating Name requires resource replacement, which is not supported.
What it means
ValidationError from the AWS::ECS::CapacityProvider provisioner when an update changes the provider's Name. Name is create-only in this implementation (replacement is not modeled), and the guard exists because a name change would otherwise mint a new provider and orphan the old one with nothing referencing it.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/EcsCapacityCfnProvisioner.java:88
// providers attached, which is what AWS does: the associations are the resource.
case ASSOCIATIONS -> clearAssociations(physicalId, region);
default -> { }
}
}
private void provisionCapacityProvider(StackResource r, JsonNode props, ProvisionContext ctx) {
String existingName = r.getPhysicalId();
String declaredName = ctx.resolveOptional(props, "Name");
// An unnamed provider keeps the name its first execution generated. Minting a fresh one on
// every pass left the previous provider behind with nothing referencing it.
String name = declaredName != null && !declaredName.isBlank()
? declaredName
: (existingName != null && !existingName.isBlank()
? existingName
: ctx.generatePhysicalName(r.getLogicalId(), 255, false));
if (existingName != null && !existingName.isBlank() && !existingName.equals(name)) {
throw new AwsException("ValidationError",
"Updating Name requires resource replacement, which is not supported.", 400);
}
Map<String, Object> asgProvider = asgProvider(props, ctx);
Map<String, String> tags = tags(props, ctx);
// UpdateStack re-executes every resource with the physical id it got at create time, and
// createCapacityProvider rejects a name that already exists, so an unchanged provider used
// to fail the whole update. An empty result also covers a provider removed out of band,
// which is recreated rather than reported as a failure.
CapacityProvider existing = existingName == null || existingName.isBlank()
? null
: ecsService.describeCapacityProviders(List.of(existingName)).stream()
.findFirst().orElse(null);
if (existing == null) {
ecsService.createCapacityProvider(name, asgProvider, tags, ctx.region());
} else {View on GitHub (pinned to 62ff490619)
Solutions
- Keep the Name property identical across updates, or omit it in both the original and updated template.
- If a rename is genuinely needed, delete and recreate the stack (or remove and re-add the resource) — replacement semantics.
- Beware the asymmetry: a resource first created unnamed keeps its generated name forever; adding a Name later will always trip this guard.
Example fix
# before (v1 omitted Name, v2 adds it) Type: AWS::ECS::CapacityProvider Properties: Name: prod-cp # conflicts with generated name from v1 # after (v2 keeps it unnamed, matching v1) Type: AWS::ECS::CapacityProvider Properties: AutoScalingGroupProvider: ...
Defensive patterns
Strategy: validation
Validate before calling
// Before UpdateStack: declared Name must equal the recorded physical id
String declared = template.stringAt("Resources/Cap/Properties/Name");
String recorded = describeStackResource(stack, "Cap").physicalResourceId();
if (declared != null && !declared.equals(recorded)) {
throw new IllegalStateException("Name change requires stack recreation");
} Try / catch
catch ValidationError "Updating Name requires resource replacement" during UpdateStack: either revert the Name in the template or delete/recreate the stack (or move the resource to a new logical id); retrying the same template always fails.
Prevention
- Decide the capacity provider's Name in v1 of the template and never change it
- Omit Name entirely if you do not need a stable one — but then never add it later
- Treat name changes as delete+create operations in deployment tooling
When it happens
Trigger: UpdateStack on a stack containing AWS::ECS::CapacityProvider where the template's Name property differs from the physical id recorded at create time — including switching from an unnamed provider to a named one.
Common situations: Renaming a capacity provider in a template between deploys, or adding a Name to a resource that was originally created without one (generated name) so the declared name never equals the stored one.
Understand the failure class
Background: ValidationError explained: why open-source libraries reject your input — file uploads, YAML manifests, unique fields, and query permissions — this error's family across 13 libraries.
Related errors
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/c6d73b31e8a26957.
Report an issue: GitHub.