JuliusBrussee/caveman · error

kms: unsupported provider

Error message

kms: unsupported provider %q

What it means

kms.New only supports the Scaleway provider; any provider value other than ProviderScaleway (case-insensitive, trimmed) is rejected at construction time so the client is always immutable and valid. The returned error names the offending value with %q so config typos are immediately visible.

Solutions

  1. Set cfg.Provider to exactly "scaleway" (case/whitespace are normalized).
  2. Check the environment variable or config file feeding cfg.Provider for stale values from another cloud.
  3. If you need another provider, this client does not support it — use that provider's SDK instead.

Example fix

// before
cfg := kms.Config{Provider: "aws-kms", Region: "fr-par", KeyID: id}
client, err := kms.New(cfg) // kms: unsupported provider "aws-kms"
// after
cfg := kms.Config{Provider: kms.ProviderScaleway, Region: "fr-par", KeyID: id}
client, err := kms.New(cfg)
Defensive patterns

Strategy: validation

Validate before calling

if strings.ToLower(strings.TrimSpace(cfg.Provider)) != "scaleway" {
    return fmt.Errorf("provider %q unsupported; only 'scaleway'", cfg.Provider)
}
client, err := kms.New(cfg)

Try / catch

client, err := kms.New(cfg)
if err != nil {
    if strings.Contains(err.Error(), "unsupported provider") {
        return fmt.Errorf("KMS misconfiguration: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling kms.New(cfg) with cfg.Provider set to "aws", "vault", "scw", "Scaleway " with odd casing is fine, but anything not exactly "scaleway" after ToLower/TrimSpace throws.

Common situations: Copy-pasting KMS config from an AWS/GCP project; an env var like KMS_PROVIDER defaulting to another cloud; typos such as "scaleway-kms" or empty provider string.

Related errors


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

Appendix: source

Thrown at shared/platform/kms/kms.go:78

	token         string
	apiBaseURL    string
	httpClient    *http.Client
	decryptKeyIDs map[string]struct{}
}

// Envelope is safe to persist. Ciphertext is opaque provider output.
type Envelope struct {
	Provider   string `json:"provider"`
	Region     string `json:"region"`
	KeyID      string `json:"key_id"`
	Ciphertext string `json:"ciphertext"`
}

// New validates configuration and returns immutable client.
func New(cfg Config) (*Client, error) {
	provider := strings.ToLower(strings.TrimSpace(cfg.Provider))
	if provider != ProviderScaleway {
		return nil, fmt.Errorf("kms: unsupported provider %q", provider)
	}
	region, keyID := strings.TrimSpace(cfg.Region), strings.TrimSpace(cfg.KeyID)
	if err := validateLocation(region, keyID); err != nil {
		return nil, err
	}
	decryptKeyIDs := map[string]struct{}{keyID: {}}
	for _, allowedKeyID := range cfg.AllowedDecryptKeyIDs {
		allowedKeyID = strings.TrimSpace(allowedKeyID)
		if err := validateLocation(region, allowedKeyID); err != nil {
			return nil, err
		}
		decryptKeyIDs[allowedKeyID] = struct{}{}
	}
	token := strings.TrimSpace(cfg.AuthToken)
	if len(token) < 20 {
		return nil, errors.New("kms: auth token is required")
	}
	baseURL := strings.TrimRight(strings.TrimSpace(cfg.APIBaseURL), "/")

View on GitHub (pinned to 3ee70a1026)