googleapis/mcp-toolbox · error
failed to delete object %q in bucket %q: %w
Error message
failed to delete object %q in bucket %q: %w
What it means
DeleteObject wraps any error returned by the GCS client's Object.Delete call with the object and bucket names. The library throws it whenever the underlying Cloud Storage API rejects or fails the delete operation; the wrapped cause (e.g. storage.ErrObjectNotExist, 403, preconditions) is preserved via %w.
Source
Thrown at internal/sources/cloudstorage/cloudstorage.go:596
return nil, fmt.Errorf("failed to move %q to %q in bucket %q: %w", sourceObject, destinationObject, bucket, err)
}
return map[string]any{
"bucket": bucket,
"sourceObject": sourceObject,
"destinationObject": destinationObject,
"bytes": attrs.Size,
"contentType": attrs.ContentType,
}, nil
}
// DeleteObject deletes a GCS object.
func (s *Source) DeleteObject(ctx context.Context, bucket, object string) (map[string]any, error) {
if err := s.validateBucket(bucket); err != nil {
return nil, err
}
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)
}
View on GitHub (pinned to 8cc6e09de2)
Solutions
- Check the wrapped cause: errors.Is(err, storage.ErrObjectNotExist) means the object is already gone — treat as success for idempotent cleanup
- Verify the credentials/service account has roles/storage.objectAdmin (or storage.objects.delete) on the bucket
- Confirm the object name exactly matches (no leading slash, correct encoding)
- Check for retention policy, event-based hold, or temporary hold on the object/bucket and lift them before deleting
- Retry on transient errors (5xx, context deadline) with backoff
Example fix
// before
_, err := src.DeleteObject(ctx, bucket, object)
if err != nil { return err }
// after
_, err := src.DeleteObject(ctx, bucket, object)
if err != nil {
if errors.Is(err, storage.ErrObjectNotExist) {
return nil // already deleted, idempotent
}
return fmt.Errorf("delete %s/%s: %w", bucket, object, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if bucket == "" || object == "" { return errors.New("bucket and object are required") } Try / catch
res, err := src.DeleteObject(ctx, bucket, object)
if err != nil {
if strings.Contains(err.Error(), "notExist") || errors.Is(err, storage.ErrObjectNotExist) {
// treat as already deleted
return nil
}
if strings.Contains(err.Error(), "403") {
// permissions problem: check IAM roles
}
return err
} Prevention
- Make delete calls idempotent by tolerating ErrObjectNotExist
- Grant the service account storage.objectAdmin on the bucket
- Verify object names with a List/Get before delete in critical flows
- Check retention/hold policies before scheduling deletes
When it happens
Trigger: Calling Source.DeleteObject(ctx, bucket, object) when the object does not exist, the caller lacks storage.objects.delete permission, a generation precondition fails (object was modified concurrently), the bucket name fails validateBucket, or a transient GCS/network error occurs.
Common situations: Deleting an already-removed object (double delete in cleanup jobs), service account missing storage.admin or objectAdmin role, deleting objects with retention/hold policies applied, typos in object names, or bucket configured with retention lock.
Related errors
- failed to delete bucket %q: %w
- unable to create client: %w
- unable to create storage.NewClient for project %q: %w
- ErrReadSizeLimitExceeded
- ErrBinaryContent
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/d984a28f5f3dad82.
Report an issue: GitHub.