router-for-me/CLIProxyAPI · error
vertex credential: service account content is empty
Error message
vertex credential: service account content is empty
What it means
Returned by VertexCredentialStorage.SaveTokenToFile when the storage's ServiceAccount map is nil (vertex_credentials.go:53-55). Saving a Vertex credential requires an actual service account payload; a zero-value storage (created but never populated) is rejected before any file I/O.
Source
Thrown at internal/auth/vertex/vertex_credentials.go:55
// Metadata holds arbitrary key-value pairs injected via hooks.
Metadata map[string]any `json:"-"`
}
// SetMetadata allows external callers to inject metadata into the storage before saving.
func (s *VertexCredentialStorage) SetMetadata(meta map[string]any) {
s.Metadata = meta
}
// SaveTokenToFile writes the credential payload to the given file path in JSON format.
// It ensures the parent directory exists and logs the operation for transparency.
func (s *VertexCredentialStorage) SaveTokenToFile(authFilePath string) error {
misc.LogSavingCredentials(authFilePath)
if s == nil {
return fmt.Errorf("vertex credential: storage is nil")
}
if s.ServiceAccount == nil {
return fmt.Errorf("vertex credential: service account content is empty")
}
// Ensure we tag the file with the provider type.
s.Type = "vertex"
if err := os.MkdirAll(filepath.Dir(authFilePath), 0o700); err != nil {
return fmt.Errorf("vertex credential: create directory failed: %w", err)
}
data, errMerge := misc.MergeMetadata(s, s.Metadata)
if errMerge != nil {
return fmt.Errorf("vertex credential: merge metadata failed: %w", errMerge)
}
f, err := os.Create(authFilePath)
if err != nil {
return fmt.Errorf("vertex credential: create file failed: %w", err)
}
defer func() {View on GitHub (pinned to 78f0c4079e)
Solutions
- Populate ServiceAccount from a valid GCP service account JSON before saving (unmarshal the key file into the map)
- Trace where the storage was built; if it comes from a loader, fix the loader so parse failures abort instead of producing nil
- Use NormalizeServiceAccountMap first to validate, then assign
Example fix
// before
s := &vertex.VertexCredentialStorage{}
err := s.SaveTokenToFile(path) // fails: service account content is empty
// after
var sa map[string]any
if err := json.Unmarshal(keyJSON, &sa); err != nil { return err }
s.ServiceAccount = sa
err := s.SaveTokenToFile(path) Defensive patterns
Strategy: validation
Validate before calling
if s.ServiceAccount == nil {
return fmt.Errorf("refusing to save vertex credential without service account payload")
} Type guard
func (s *VertexCredentialStorage) isPopulated() bool {
return s != nil && s.ServiceAccount != nil
} Prevention
- Populate storage from a validated JSON key before saving
- Abort load pipelines on parse failure instead of continuing with nil
- Unit-test save paths with fully populated fixtures
When it happens
Trigger: Calling SaveTokenToFile on a newly constructed VertexCredentialStorage without setting ServiceAccount; a load path that failed to parse the JSON but continued with a nil map; programmatic embedding skipping the population step.
Common situations: SDK embedders constructing the storage manually; a partial import/migration that writes credential records before the account content is attached; tests exercising the save path with fixtures lacking the account.
Related errors
- service account payload is empty
- source auth path is empty
- auth path is empty
- auth id is empty
- select Claude device ID: session ID is empty
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/f3b662d2c59023bf.
Report an issue: GitHub.