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

  1. Populate ServiceAccount from a valid GCP service account JSON before saving (unmarshal the key file into the map)
  2. Trace where the storage was built; if it comes from a loader, fix the loader so parse failures abort instead of producing nil
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/f3b662d2c59023bf. Report an issue: GitHub.