googleapis/mcp-toolbox · error

failed to delete bucket %q: %w

Error message

failed to delete bucket %q: %w

What it means

DeleteBucket wraps any error from the GCS client's Bucket.Delete call with the bucket name. The library throws it because GCS only allows deleting empty buckets and requires delete permission; the underlying cause (not empty, 403, not found) is preserved via %w.

Source

Thrown at internal/sources/cloudstorage/cloudstorage.go:612

	}
	if err := s.client.Bucket(bucket).Object(object).Delete(ctx); err != nil {
		return nil, fmt.Errorf("failed to delete object %q in bucket %q: %w", object, bucket, err)
	}

	return map[string]any{
		"bucket":  bucket,
		"object":  object,
		"deleted": true,
	}, nil
}

// DeleteBucket deletes an empty Cloud Storage bucket.
func (s *Source) DeleteBucket(ctx context.Context, bucket string) (map[string]any, error) {
	if err := s.validateBucket(bucket); err != nil {
		return nil, err
	}
	if err := s.client.Bucket(bucket).Delete(ctx); err != nil {
		return nil, fmt.Errorf("failed to delete bucket %q: %w", bucket, err)
	}

	return map[string]any{
		"bucket":  bucket,
		"deleted": true,
	}, nil
}

func initGCSClient(ctx context.Context, tracer trace.Tracer, name, project string) (*storage.Client, error) {
	//nolint:all // Reassigned ctx
	ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name)
	defer span.End()

	userAgent, err := util.UserAgentFromContext(ctx)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Empty the bucket first: delete all objects (and object versions / soft-deleted copies, e.g. via gsutil rm -r or storage buckets objects list with versions)
  2. Check the wrapped cause: storage.ErrBucketNotExist vs 403 vs 'bucket not empty' to pick the fix
  3. Grant the service account roles/storage.admin or at minimum storage.buckets.delete
  4. Remove or expire any retention policy/lifecycle locks before deletion
  5. Retry transient 5xx errors with backoff

Example fix

// before
if err := emptyBucketObjects(ctx, src, bucket); err != nil { return err }
_, err := src.DeleteBucket(ctx, bucket)
// after
if err := emptyBucketObjects(ctx, src, bucket); err != nil { return err }
if err := purgeObjectVersionsAndSoftDeleted(ctx, src, bucket); err != nil { return err }
_, err := src.DeleteBucket(ctx, bucket)
Defensive patterns

Strategy: validation

Validate before calling

// Before DeleteBucket, ensure bucket is empty (including versions/soft-deleted)
func bucketIsEmpty(ctx context.Context, src *cloudstorage.Source, bucket string) (bool, error) {
    it, err := src.ListObjects(ctx, bucket, "")
    if err != nil { return false, err }
    return len(it) == 0, nil
}

Try / catch

_, err := src.DeleteBucket(ctx, bucket)
if err != nil {
    switch {
    case strings.Contains(err.Error(), "not empty"):
        // purge remaining objects/versions then retry
    case strings.Contains(err.Error(), "403"):
        // fix IAM
    default:
        return err
    }
}

Prevention

When it happens

Trigger: Calling Source.DeleteBucket(ctx, bucket) when the bucket still contains objects (including object versions/soft-deleted objects), the caller lacks storage.buckets.delete permission, the bucket does not exist, the bucket name fails validateBucket, or a transient API error occurs.

Common situations: Trying to delete a bucket that appears empty but holds non-current object versions or soft-deleted objects, service account missing roles/storage.admin, deleting a bucket with retention policy or public access prevention conflicts, environment pointing at a region where the bucket doesn't exist.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/2f0d632525429ab8. Report an issue: GitHub.