Skip to content

StaticSite: BucketFiles deletion fails when asset bucket is already absent #6963

Description

@bjorntechTobbe

Summary

sst remove fails when a StaticSite asset bucket is already absent because the internal BucketFiles resource treats S3 NoSuchBucket as a fatal deletion error.

Deletion should be idempotent when the bucket and all managed objects no longer exist.

Environment

  • SST: 4.14.3
  • Confirmed still present in SST 4.17.1 and current dev
  • AWS region: eu-north-1
  • Platform: macOS arm64
  • Component: sst.aws.StaticSite

Reproduction

  1. Deploy an sst.aws.StaticSite.
  2. Delete its generated asset bucket externally, or interrupt a removal after the bucket has been deleted.
  3. Run sst remove.
  4. The BucketFiles resource attempts to delete its recorded objects from the missing bucket.

Actual behavior

Web sst:aws:StaticSite -> WebAssetFiles sst:aws:BucketFiles

operation error S3: DeleteObject
StatusCode: 404
NoSuchBucket: The specified bucket does not exist

The stage remains partially removed. Recovery requires manually removing the BucketFiles dynamic resource from state and rerunning sst remove.

Expected behavior

BucketFiles.Delete should treat NoSuchBucket as successful deletion. Other S3 errors should remain fatal.

Source review

Current dev still delegates deletion directly to purge:

https://github.com/anomalyco/sst/blob/dev/pkg/server/resource/aws-bucket-files.go

func (r *BucketFiles) Delete(...) error {
    // ...
    return r.purge(s3Client, input.Outs.BucketName, nil, input.Outs.Files)
}

purge returns the first DeleteObject error without classifying NoSuchBucket. Since purge is also used during updates, the idempotent handling should be limited to Delete.

Suggested fix / PR

  1. Detect typed *s3types.NoSuchBucket errors in BucketFiles.Delete.
  2. Defensively recognize a Smithy APIError with code NoSuchBucket.
  3. Return success only from the delete lifecycle path.
  4. Keep missing buckets fatal during create/update.
  5. Avoid a preliminary HeadBucket, which would add a request and retain a check/delete race.

Suggested tests:

  • Missing bucket during delete returns success.
  • Missing bucket during update remains an error.
  • AccessDenied and other S3 errors remain errors.
  • Existing-bucket deletion remains unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions