-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Description
When using storage.NewClient() with explicit credential options like option.WithCredentialsFile(), option.WithCredentialsJSON(), or option.WithAuthCredentialsFile(), the client fails with:
dialing: multiple credential options provided
This affects cloud.google.com/go/storage v1.55.0 and later.
Root Cause
The bug was introduced by two PRs merged into v1.55.0:
- PR fix(storage): migrate oauth2/google usages to cloud.google.com/go/auth #11191 (merged May 14, 2025) - Added
internaloption.AuthCreds()call that parses user-provided credential options and appendsoption.WithAuthCredentials(creds) - PR fix(storage): add EnableNewAuthLibrary internalOption to HTTP newClient #12320 (merged May 28, 2025) - Added
internaloption.EnableNewAuthLibrary()which enables the new auth library validation
In storage.go NewClient() (lines 167-175):
// PR #12320 added this:
internaloption.EnableNewAuthLibrary(),
// PR #11191 added this:
c, err := internaloption.AuthCreds(ctx, opts)
if err == nil {
creds = c
opts = append(opts, option.WithAuthCredentials(creds)) // Duplicates credentials!
}When a user passes any credential option:
- The credential option is already in
opts AuthCreds()parses it into anauth.CredentialsobjectWithAuthCredentials(creds)is appended - creating a second credential option- Validation in
google.golang.org/api/internal/settings.go:199-200fails becausenCreds > 1
Steps to Reproduce
package main
import (
"context"
"fmt"
"cloud.google.com/go/storage"
"google.golang.org/api/option"
)
func main() {
ctx := context.Background()
// Any of these will fail:
_, err := storage.NewClient(ctx, option.WithCredentialsFile("/path/to/service-account.json"))
// OR: _, err := storage.NewClient(ctx, option.WithCredentialsJSON([]byte(`{"type":"service_account",...}`)))
// OR: _, err := storage.NewClient(ctx, option.WithAuthCredentialsFile(option.ServiceAccount, "/path/to/creds.json"))
if err != nil {
fmt.Printf("Error: %v\n", err) // "dialing: multiple credential options provided"
}
}Expected Behavior
The storage client should accept explicit credential options without duplicating them internally. The AuthCreds() call should detect that credentials were already provided and skip appending WithAuthCredentials().
Workaround
Set GOOGLE_APPLICATION_CREDENTIALS environment variable instead of passing credential options:
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/creds.json")
client, err := storage.NewClient(ctx) // Uses ADC, works correctlyEnvironment
cloud.google.com/go/storage: v1.55.0+ (tested on v1.58.0)google.golang.org/api: v0.258.0- Go version: 1.24.6
- OS: Linux (Docker container)
Suggested Fix
Before appending WithAuthCredentials, check if the user already provided credentials:
c, err := internaloption.AuthCreds(ctx, opts)
if err == nil {
creds = c
// Only append if user didn't already provide credentials
if !hasExplicitCredentials(opts) {
opts = append(opts, option.WithAuthCredentials(creds))
}
}Or alternatively, don't append at all since AuthCreds already parsed the user's credentials and they're stored in the creds variable for later use.
Related Issues
- storage: Loading creds during NewClient breaks application without default creds #4980 - Similar credential handling issue (fixed, but different root cause)