getsops/sops · error

no valid resource ID found in %q

Error message

no valid resource ID found in %q

What it means

newKMSClient validates that MasterKey.ResourceID matches the canonical GCP KMS crypto key path `projects/.../locations/.../keyRings/.../cryptoKeys/...` via regex. Anything else — aliases, partial paths, URLs, extra segments — is rejected before creating the client.

Source

Thrown at gcpkms/keysource.go:294

	out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339)
	out["enc"] = key.EncryptedKey
	return out
}

// TypeToIdentifier returns the string identifier for the MasterKey type.
func (key *MasterKey) TypeToIdentifier() string {
	return KeyTypeIdentifier
}

// newKMSClient returns a GCP KMS client configured with the tokenSource
// or credentialJSON, and/or grpcConn, falling back to environmental defaults.
// It returns an error if the ResourceID is invalid, or if the setup of the
// client fails.
func (key *MasterKey) newKMSClient(ctx context.Context) (*kms.KeyManagementClient, error) {
	re := regexp.MustCompile(`^projects/[^/]+/locations/[^/]+/keyRings/[^/]+/cryptoKeys/[^/]+$`)
	matches := re.FindStringSubmatch(key.ResourceID)
	if matches == nil {
		return nil, fmt.Errorf("no valid resource ID found in %q", key.ResourceID)
	}

	var opts []option.ClientOption
	switch {
	case key.tokenSource != nil:
		opts = append(opts, option.WithTokenSource(key.tokenSource))
	case key.credentialJSON != nil:
		opts = append(opts, option.WithCredentialsJSON(key.credentialJSON))
	default:
		credentials, err := getGoogleCredentials()
		if err != nil {
			return nil, fmt.Errorf("credentials: failed to obtain credentials from %q: %w", SopsGoogleCredentialsEnv, err)
		}
		if credentials != nil {
			opts = append(opts, option.WithCredentialsJSON(credentials))
			break
		}

View on GitHub (pinned to 13442bb981)

Solutions

  1. Set ResourceID to the full canonical path, e.g. projects/my-proj/locations/us-east1/keyRings/sops/cryptoKeys/sops-key.
  2. Generate it with: gcloud kms keys describe KEY --location L --keyring R --format 'value(name)'.
  3. Trim whitespace and remove any 'https://...' prefix or query string.
  4. If using key alternatives versions, reference the cryptoKey, not the cryptoKeyVersion.

Example fix

// before
// resource_ids: ['projects/my-proj/locations/global/keyRings/sops']
// after
// resource_ids: ['projects/my-proj/locations/global/keyRings/sops/cryptoKeys/my-key']
Defensive patterns

Strategy: validation

Validate before calling

var gcpKeyRe = regexp.MustCompile(`^projects/[^/]+/locations/[^/]+/keyRings/[^/]+/cryptoKeys/[^/]+$`)
func validGCPResourceID(id string) bool { return gcpKeyRe.MatchString(strings.TrimSpace(id)) }

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: EncryptContext/DecryptContext (and their tests) called with a MasterKey whose ResourceID is not exactly projects/P/locations/L/keyRings/R/cryptoKeys/K, e.g. a bare key name or a global-key path.

Common situations: Writing .sops.yaml creation rules by hand and using the key ring path instead of the crypto key path; copying a console URL fragment; omitting the location (e.g. using 'global' incorrectly); trailing slashes or whitespace.

Related errors


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/a13bfbb36d197f7e. Report an issue: GitHub.