anomalyco/sst · error

failed to delete state object %s version %s: %s

Error message

failed to delete state object %s version %s: %s

What it means

`deleteObjectVersions` batch-deletes S3 object versions (used by `pruneNoncurrentVersions` and `purge` when resetting stage state). AWS `DeleteObjects` returns per-object errors in the response body rather than via the Go error, so when `out.Errors` is non-empty SST surfaces the first one with the key, version ID, and AWS message.

Source

Thrown at pkg/project/provider/aws.go:789

	return ids
}

func (a *AwsHome) deleteObjectVersions(s3Client *s3.Client, bucket string, ids []s3types.ObjectIdentifier) error {
	for i := 0; i < len(ids); i += 1000 {
		end := i + 1000
		if end > len(ids) {
			end = len(ids)
		}
		out, err := s3Client.DeleteObjects(context.TODO(), &s3.DeleteObjectsInput{
			Bucket: aws.String(bucket),
			Delete: &s3types.Delete{Objects: ids[i:end], Quiet: aws.Bool(true)},
		})
		if err != nil {
			return err
		}
		if len(out.Errors) > 0 {
			item := out.Errors[0]
			return fmt.Errorf("failed to delete state object %s version %s: %s", aws.ToString(item.Key), aws.ToString(item.VersionId), aws.ToString(item.Message))
		}
	}
	return nil
}

func (a *AwsHome) purge(app, stage string) error {
	bootstrap, err := a.provider.Bootstrap(a.provider.config.Region)
	if err != nil {
		return err
	}
	s3Client := s3.NewFromConfig(a.provider.config)

	prefixes := []string{
		a.pathForData("app", app, stage),
		a.pathForData("secret", app, stage),
		path.Join("update", app, stage) + "/",
		path.Join("summary", app, stage) + "/",
		path.Join("eventlog", app, stage) + "/",

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Read the `%s` message suffix for the concrete AWS reason (AccessDenied, InvalidRequest, etc.) and fix accordingly
  2. Grant the credentials `s3:DeleteObjectVersion` on the state bucket and its contents
  3. If Object Lock/retention is set, wait out or remove the retention before purging
Defensive patterns

Strategy: retry

Validate before calling

aws iam simulate-principal-policy --policy-source-arn <deploy-role-arn> --action-names s3:DeleteObjectVersion s3:DeleteObject --resource-arns arn:aws:s3:::sst-state-bucket/*

Try / catch

err := sstPurge(ctx, app, stage)
if err != nil && strings.Contains(err.Error(), "failed to delete state object") {
    if strings.Contains(err.Error(), "AccessDenied") {
        // fix IAM, then retry once
        err = sstPurge(ctx, app, stage)
    }
}

Prevention

When it happens

Trigger: Purging a stage (`sst purge`/unlock flow) or pruning noncurrent versions when at least one object version cannot be deleted — e.g. `AccessDenied`, version-controlled object protected by policy, or retention/legal hold.

Common situations: Bucket policies denying `s3:DeleteObjectVersion`; S3 Object Lock retention on state files; IAM missing `s3:DeleteObjectVersion` while having `s3:DeleteObject`.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/de1dd39cc9242baf. Report an issue: GitHub.