Tencent/WeKnora · error

failed to check bucket: %w

Error message

failed to check bucket: %w

What it means

NewMinioFileService calls BucketExists on the freshly built minio-go client and wraps any transport/API error as "failed to check bucket: %w". Unlike the not-exists case (which triggers MakeBucket), this error means the existence check itself could not be completed — the SDK call returned a network, TLS, authentication, or S3 API error.

Source

Thrown at internal/application/service/file/minio.go:60

	if err != nil {
		return nil, fmt.Errorf("failed to initialize MinIO client: %w", err)
	}
	return &minioFileService{client: client, bucketName: bucketName}, nil
}

// NewMinioFileService creates a MinIO file service.
// It verifies that the bucket exists and creates it if missing.
func NewMinioFileService(endpoint,
	accessKeyID, secretAccessKey, bucketName string, useSSL bool,
) (interfaces.FileService, error) {
	svc, err := newMinioClient(endpoint, accessKeyID, secretAccessKey, bucketName, useSSL)
	if err != nil {
		return nil, err
	}

	exists, err := svc.client.BucketExists(context.Background(), bucketName)
	if err != nil {
		return nil, fmt.Errorf("failed to check bucket: %w", err)
	}
	if !exists {
		if err = svc.client.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{}); err != nil {
			return nil, fmt.Errorf("failed to create bucket: %w", err)
		}
	}

	return svc, nil
}

// CheckConnectivity verifies MinIO is reachable and, if a bucket is configured,
// that the bucket exists. This is a read-only probe — it never creates a bucket.
func (s *minioFileService) CheckConnectivity(ctx context.Context) error {
	checkCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	if s.bucketName != "" {
		exists, err := s.client.BucketExists(checkCtx, s.bucketName)

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Verify MinIO is reachable from the app: curl/nc the endpoint host:port from inside the container; fix the endpoint or start the MinIO service
  2. Match the SSL setting to the server: set MINIO_USE_SSL=false for plain HTTP MinIO or true only when the server has TLS enabled (check for tls handshake errors in the wrapped cause)
  3. Verify MINIO_ACCESS_KEY/MINIO_SECRET_KEY against the server's credentials (mc alias set + mc ls to test independently)
  4. Check network egress: docker network, Kubernetes NetworkPolicy, or firewall rules may block port 9000
  5. Retry with backoff if MinIO is starting concurrently (startup race in compose); consider readiness probes ordering

Example fix

// before (compose)
MINIO_USE_SSL=true   # minio running without TLS -> handshake error
// after
MINIO_USE_SSL=false  # plain-HTTP local MinIO; enable TLS before flipping to true
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", endpointHostPort, 3*time.Second)
if err != nil {
    return fmt.Errorf("MinIO endpoint %s unreachable before client init: %w", endpointHostPort, err)
}
conn.Close()
if useSSL {
    // verify TLS works; a plaintext server will fail BucketExists
    if _, err := tls.Dial("tcp", endpointHostPort, nil); err != nil {
        return fmt.Errorf("TLS handshake failed; check MINIO_USE_SSL: %w", err)
    }
}

Try / catch

svc, err := file.NewMinioFileService(endpoint, ak, sk, bucket, useSSL)
if err != nil && strings.Contains(err.Error(), "failed to check bucket") {
    // transient (MinIO starting up / network blip): retry with backoff
    var re *minio.ErrorResponse
    if errors.As(err, &re) && re.Code == "SignatureDoesNotMatch" {
        return fmt.Errorf("bad MinIO credentials, do not retry: %w", err)
    }
    return retry.WithBackoff(3, func() error {
        svc, err = file.NewMinioFileService(endpoint, ak, sk, bucket, useSSL)
        return err
    })
} else if err != nil {
    return err
}

Prevention

When it happens

Trigger: svc.client.BucketExists(context.Background(), bucketName) returns an error: MinIO host unreachable (connection refused/DNS failure), TLS handshake failure when useSSL=true against a plaintext endpoint (or vice versa), invalid access/secret keys rejected by the server (SignatureDoesNotMatch/AccessDenied), or no network egress from the container.

Common situations: MinIO not yet started or wrong port in docker-compose; MINIO_USE_SSL=true while the server only serves HTTP (tls: first record does not look like a TLS handshake); wrong MINIO_ACCESS_KEY/SECRET_KEY; egress firewall or missing NetworkPolicy in Kubernetes; DNS name typo in the endpoint.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/c9b55ad024e2c283. Report an issue: GitHub.