{"record":{"id":"19e10c21f793b3ed","repo":"floci-io/floci","slug":"stacksetnotemptyexception","errorCode":"StackSetNotEmptyException","errorMessage":"StackSet is not empty. Delete all stack instances first.","messagePattern":"StackSet is not empty\\. Delete all stack instances first\\.","errorType":"error_code","errorClass":"AwsException","httpStatus":409,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/cloudformation/StackSetService.java","lineNumber":137,"sourceCode":"        if (description != null) {\n            ss.setDescription(description);\n        }\n        stackSets.put(name, ss);\n\n        // Re-apply the updated definition to every existing instance, refreshing each record.\n        List<StackInstance> deployed = new ArrayList<>();\n        for (StackInstance inst : listStackInstances(name, null, null)) {\n            StackInstance updated = deployInstance(ss, inst.getAccount(), inst.getRegion(), UPDATE_CHANGE_SET, \"UPDATE\");\n            instances.put(instanceKey(name, updated.getAccount(), updated.getRegion()), updated);\n            deployed.add(updated);\n        }\n        return recordOperation(name, \"UPDATE\", deriveOperationStatus(deployed));\n    }\n\n    public void deleteStackSet(String name) {\n        getStackSetOrThrow(name);\n        if (!listStackInstances(name, null, null).isEmpty()) {\n            throw new AwsException(\"StackSetNotEmptyException\",\n                    \"StackSet is not empty. Delete all stack instances first.\", 409);\n        }\n        stackSets.delete(name);\n        LOG.infov(\"Deleted StackSet: {0}\", name);\n    }\n\n    // ── Instances ──────────────────────────────────────────────────────────────\n\n    public StackSetOperation createStackInstances(String name, List<String> accounts, List<String> regions) {\n        StackSet ss = getStackSetOrThrow(name);\n        if (accounts == null || accounts.isEmpty() || regions == null || regions.isEmpty()) {\n            throw new AwsException(\"ValidationError\",\n                    \"Accounts and Regions must each contain at least one value\", 400);\n        }\n        List<StackInstance> deployed = new ArrayList<>();\n        for (String account : accounts) {\n            for (String region : regions) {\n                StackInstance inst = deployInstance(ss, account, region, INSTANCE_CHANGE_SET, \"CREATE\");","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/cloudformation/StackSetService.java#L119-L155","documentation":"StackSetNotEmptyException (HTTP 409) from deleteStackSet when the StackSet still has stack instances. Floci enforces AWS's ordering: every (account, region) instance must be deleted (or retained) via DeleteStackInstances before the StackSet itself can be removed.","triggerScenarios":"DeleteStackSet called while instances exist — i.e., CreateStackInstances ran earlier and DeleteStackInstances was never called, or was called with a subset of accounts/regions.","commonSituations":"Cleanup scripts that delete only the StackSet, forgetting the instance layer; DeleteStackInstances invoked with fewer accounts/regions than were created; asynchronous instance deletion not yet finished when DeleteStackSet is issued.","solutions":["List remaining instances: aws ... cloudformation list-stack-instances --stack-set-name <name>.","Delete all instances: aws ... cloudformation delete-stack-instances --stack-set-name <name> --accounts <a> --regions <r> --no-retain-stacks (repeat for every account/region pair).","Then call DeleteStackSet.","Use --retain-stacks instead of --no-retain-stacks only if you intentionally want the underlying stacks left in place."],"exampleFix":"# before\naws ... cloudformation delete-stack-set --stack-set-name shared\n\n# after\naws ... cloudformation delete-stack-instances --stack-set-name shared \\\n  --accounts 111122223333 --regions us-east-1 --no-retain-stacks\naws ... cloudformation delete-stack-set --stack-set-name shared","handlingStrategy":"validation","validationCode":"var remaining = cfn.listStackInstances(req -> req.stackSetName(name)).summaries();\nif (!remaining.isEmpty()) {\n    // delete every (account, region) pair first\n    remaining.forEach(i -> cfn.deleteStackInstances(req -> req\n        .stackSetName(name).accounts(i.account()).regions(i.region()).retainStacks(false)));\n}\ncfn.deleteStackSet(req -> req.stackSetName(name));","typeGuard":null,"tryCatchPattern":"catch StackSetNotEmptyException (409): call ListStackInstances, issue DeleteStackInstances for every account/region pair with --no-retain-stacks, wait for the operation to finish, then retry DeleteStackSet once.","preventionTips":["Teardown order: instances before stack set, always","Pass --no-retain-stacks unless the underlying stacks must survive","Drive deletion from ListStackInstances output so no pair is missed"],"tags":["cloudformation","stacksets","delete-ordering","conflict"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}