{"record":{"id":"2edb637a8e14de11","repo":"larksuite/cli","slug":"unsupported-secret-source-q","errorCode":null,"errorMessage":"unsupported secret source %q","messagePattern":"unsupported secret source %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/binding/secret_resolve.go","lineNumber":79,"sourceCode":"\tproviderConfig, err := LookupProvider(ref, cfg)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Resolve the effective provider name once so downstream resolvers\n\t// (notably the exec JSON payload) see the config-defaulted value instead\n\t// of the unset literal on ref.Provider.\n\tproviderName := ResolveDefaultProvider(ref, cfg)\n\n\tswitch ref.Source {\n\tcase \"env\":\n\t\treturn resolveEnvRef(ref, providerConfig, getenv)\n\tcase \"file\":\n\t\treturn resolveFileRef(ref, providerConfig)\n\tcase \"exec\":\n\t\treturn resolveExecRef(ref, providerName, providerConfig, getenv)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unsupported secret source %q\", ref.Source)\n\t}\n}\n\n// resolveEnvRef handles {source:\"env\"} SecretRef.\nfunc resolveEnvRef(ref *SecretRef, pc *ProviderConfig, getenv func(string) string) (string, error) {\n\t// Check allowlist if configured\n\tif len(pc.Allowlist) > 0 {\n\t\tallowed := false\n\t\tfor _, name := range pc.Allowlist {\n\t\t\tif name == ref.ID {\n\t\t\t\tallowed = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !allowed {\n\t\t\treturn \"\", fmt.Errorf(\"environment variable %q is not allowlisted in provider\", ref.ID)\n\t\t}\n\t}","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/binding/secret_resolve.go#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use one of the supported sources exactly: \"env\", \"file\", or \"exec\" in the SecretRef.","For a real secret manager, use source:\"exec\" with a command that fetches the secret from vault/kms and prints the value.","In code, validate before calling: if !validSources[ref.Source] (or a local switch on the same set) reject early.","If going through JSON, rely on UnmarshalJSON which rejects bad sources earlier with its own clearer message."],"exampleFix":"// before\nref := &binding.SecretRef{Source: \"vault\", ID: \"feishu/secret\"}\n// after\nref := &binding.SecretRef{Source: \"exec\", ID: \"feishu/secret\"} // exec command fetches from vault","handlingStrategy":"type-guard","validationCode":"func validateSecretRef(ref *binding.SecretRef) error {\n\tswitch ref.Source {\n\tcase \"env\", \"file\", \"exec\":\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"source must be env|file|exec, got %q\", ref.Source)\n\t}\n}","typeGuard":"func isSupportedSource(src string) bool {\n\treturn src == \"env\" || src == \"file\" || src == \"exec\"\n}","tryCatchPattern":"secret, err := binding.ResolveSecretInput(binding.SecretInput{Ref: ref}, cfg, os.Getenv)\nif err != nil {\n\tif strings.HasPrefix(err.Error(), \"unsupported secret source\") {\n\t\treturn fmt.Errorf(\"use source env|file|exec (for vault/kms use exec): %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Only build SecretRef values through JSON decoding, where UnmarshalJSON validates source upfront.","Treat exec as the escape hatch for unsupported backends (vault, kms) instead of inventing a new source.","Match source strings exactly: lowercase, no whitespace, no URL schemes like \"file://\".","Centralize SecretRef construction in one helper that validates against the env|file|exec set."],"tags":["config","secrets","unsupported-value"],"backgroundTag":"unsupported-secret-source","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}