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

  1. Keep the Name property identical across updates, or omit it in both the original and updated template.
  2. If a rename is genuinely needed, delete and recreate the stack (or remove and re-add the resource) — replacement semantics.
  3. 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

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.