JuliusBrussee/caveman · error

objectstore: delete

Error message

objectstore: delete %q: %w

What it means

minioStore.Delete wraps a failure from client.RemoveObject. It means the object store rejected or failed the removal request — not that the key was absent (RemoveObject is idempotent and typically succeeds for missing keys). The key is embedded in the message and the underlying error is preserved with %w.

Solutions

  1. Check the wrapped error via minio.ToErrorResponse for AccessDenied and fix bucket/IAM policy to allow s3:DeleteObject.
  2. Retry on transient 5xx/network errors with backoff.
  3. Verify the bucket name and endpoint in the store configuration.
  4. Confirm credentials are valid and not expired (mc admin or console).
  5. Check bucket versioning/retention (object lock) rules that may block removal.

Example fix

// before
err := store.Delete(ctx, key)
// after
if err := store.Delete(ctx, key); err != nil {
    var minioErr minio.ErrorResponse
    if errors.As(err, &minioErr) && minioErr.Code == "AccessDenied" {
        return fmt.Errorf("delete %s: missing s3:DeleteObject permission: %w", key, err)
    }
    return err
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := store.Delete(ctx, key); err != nil {
    var mr minio.ErrorResponse
    if errors.As(err, &mr) && mr.Code == "AccessDenied" {
        // surface as config/permission problem, do not retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling Delete(ctx, key) (directly or via deleteVersions from DeleteAllVersions) when RemoveObject returns a non-nil error: permission denied on the bucket, network failure, wrong bucket name, read-only bucket policy, or storage backend outage.

Common situations: IAM/bucket policy lacking s3:DeleteObject; pointing at a versioned bucket where policies block deletes; transient MinIO/S3 5xx; misconfigured bucket after environment change; Docker-compose MinIO restarted with different credentials.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/4f117ee95a517c96. Report an issue: GitHub.

Appendix: source

Thrown at shared/platform/objectstore/objectstore.go:308

	if maxBytes <= 0 {
		maxBytes = 64 << 20
	}
	body, err := io.ReadAll(io.LimitReader(obj, maxBytes+1))
	if err != nil {
		if minio.ToErrorResponse(err).Code == "NoSuchKey" {
			return nil, ErrNotFound
		}
		return nil, fmt.Errorf("objectstore: read %q: %w", key, err)
	}
	if int64(len(body)) > maxBytes {
		return nil, ErrTooLarge
	}
	return body, nil
}

func (m *minioStore) Delete(ctx context.Context, key string) error {
	if err := m.client.RemoveObject(ctx, m.bucket, key, minio.RemoveObjectOptions{}); err != nil {
		return fmt.Errorf("objectstore: delete %q: %w", key, err)
	}
	return nil
}

func (m *minioStore) DeleteAllVersions(ctx context.Context, key string) error {
	return m.deleteVersions(ctx, key, true)
}

func (m *minioStore) DeletePrefixAllVersions(ctx context.Context, prefix string) error {
	return m.deleteVersions(ctx, prefix, false)
}

func (m *minioStore) deleteVersions(ctx context.Context, keyOrPrefix string, exact bool) error {
	found := false
	for obj := range m.client.ListObjects(ctx, m.bucket, minio.ListObjectsOptions{
		Prefix: keyOrPrefix, Recursive: true, WithVersions: true,
	}) {
		if obj.Err != nil {

View on GitHub (pinned to 3ee70a1026)