larksuite/cli · error

unsupported secret source %q

Error message

unsupported secret source %q

What it means

When a SecretInput is the object form, resolveSecretRef dispatches on SecretRef.Source to env/file/exec sub-resolvers. This error means Source held a value outside that set, so no sub-resolver applies. It is normally unreachable for JSON-parsed input because SecretInput.UnmarshalJSON validates source upfront; it fires for programmatically constructed SecretRef values (tests, plugin code) that bypass JSON decoding, or if ref.Source is mutated after unmarshal.

Source

Thrown at internal/binding/secret_resolve.go:79

	providerConfig, err := LookupProvider(ref, cfg)
	if err != nil {
		return "", err
	}

	// Resolve the effective provider name once so downstream resolvers
	// (notably the exec JSON payload) see the config-defaulted value instead
	// of the unset literal on ref.Provider.
	providerName := ResolveDefaultProvider(ref, cfg)

	switch ref.Source {
	case "env":
		return resolveEnvRef(ref, providerConfig, getenv)
	case "file":
		return resolveFileRef(ref, providerConfig)
	case "exec":
		return resolveExecRef(ref, providerName, providerConfig, getenv)
	default:
		return "", fmt.Errorf("unsupported secret source %q", ref.Source)
	}
}

// resolveEnvRef handles {source:"env"} SecretRef.
func resolveEnvRef(ref *SecretRef, pc *ProviderConfig, getenv func(string) string) (string, error) {
	// Check allowlist if configured
	if len(pc.Allowlist) > 0 {
		allowed := false
		for _, name := range pc.Allowlist {
			if name == ref.ID {
				allowed = true
				break
			}
		}
		if !allowed {
			return "", fmt.Errorf("environment variable %q is not allowlisted in provider", ref.ID)
		}
	}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Use one of the supported sources exactly: "env", "file", or "exec" in the SecretRef.
  2. For a real secret manager, use source:"exec" with a command that fetches the secret from vault/kms and prints the value.
  3. In code, validate before calling: if !validSources[ref.Source] (or a local switch on the same set) reject early.
  4. If going through JSON, rely on UnmarshalJSON which rejects bad sources earlier with its own clearer message.

Example fix

// before
ref := &binding.SecretRef{Source: "vault", ID: "feishu/secret"}
// after
ref := &binding.SecretRef{Source: "exec", ID: "feishu/secret"} // exec command fetches from vault
Defensive patterns

Strategy: type-guard

Validate before calling

func validateSecretRef(ref *binding.SecretRef) error {
	switch ref.Source {
	case "env", "file", "exec":
		return nil
	default:
		return fmt.Errorf("source must be env|file|exec, got %q", ref.Source)
	}
}

Type guard

func isSupportedSource(src string) bool {
	return src == "env" || src == "file" || src == "exec"
}

Try / catch

secret, err := binding.ResolveSecretInput(binding.SecretInput{Ref: ref}, cfg, os.Getenv)
if err != nil {
	if strings.HasPrefix(err.Error(), "unsupported secret source") {
		return fmt.Errorf("use source env|file|exec (for vault/kms use exec): %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Constructing SecretRef{Source: "kms" | "vault" | "" | "env " (with space)} in Go and calling ResolveSecretInput directly, or any code path that builds the union without going through UnmarshalJSON's validSources check. Note provider *names* are resolved via config; only Source is switch-matched here.

Common situations: A developer extends the ref with a new backend (e.g. source:"vault") expecting library support that does not exist yet; a typo like "Environment" or "file://" in a programmatically built ref; test fixtures with placeholder sources.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/2edb637a8e14de11. Report an issue: GitHub.