larksuite/cli · error
unknown secret source: %s
Error message
unknown secret source: %s
What it means
ResolveSecretInput switches on the SecretRef source and only understands file and keychain (the ValidSecretSources set). This error is returned when the config's secret reference names a source outside that set, so the secret cannot be resolved.
Source
Thrown at internal/core/secret_resolve.go:36
}
// ResolveSecretInput resolves a SecretInput to a plain string.
// SecretRef objects are resolved by source (file / keychain).
func ResolveSecretInput(s SecretInput, kc keychain.KeychainAccess) (string, error) {
if s.Ref == nil {
return s.Plain, nil
}
switch s.Ref.Source {
case "file":
data, err := vfs.ReadFile(s.Ref.ID)
if err != nil {
return "", fmt.Errorf("failed to read secret file %s: %w", s.Ref.ID, err)
}
return strings.TrimSpace(string(data)), nil
case "keychain":
return kc.Get(keychain.LarkCliService, s.Ref.ID)
default:
return "", fmt.Errorf("unknown secret source: %s", s.Ref.Source)
}
}
// ForStorage determines how to store a secret in config.json.
// - SecretRef → preserved as-is
// - Plain text → stored in keychain, returns keychain SecretRef
// Returns error if keychain is unavailable (no silent plaintext fallback).
func ForStorage(appId string, input SecretInput, kc keychain.KeychainAccess) (SecretInput, error) {
if !input.IsPlain() {
return input, nil // SecretRef → keep as-is
}
key := secretAccountKey(appId)
if err := kc.Set(keychain.LarkCliService, key, input.Plain); err != nil {
return SecretInput{}, fmt.Errorf("keychain unavailable: %w\nhint: use file: reference in config to bypass keychain", err)
}
return SecretInput{Ref: &SecretRef{Source: "keychain", ID: key}}, nil
}
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Change source to file and point id at a file containing the secret.
- Or change source to keychain with the account key as id (re-run the CLI's config/login flow to store it).
- Check spelling and case: only lowercase file and keychain are valid per ValidSecretSources.
- If migrating from another secret manager, export the value to a file or the OS keychain first, then reference it.
Example fix
// before (config.json)
"appSecret": {"source": "env", "id": "LARK_APP_SECRET"}
// after
"appSecret": {"source": "keychain", "id": "cli_a1b2c3:appSecret"} Defensive patterns
Strategy: validation
Validate before calling
if ref := cfg.AppSecret.Ref; ref != nil && !core.ValidSecretSources[ref.Source] {
return fmt.Errorf("unsupported secret source %q; use file or keychain", ref.Source)
} Type guard
func knownSecretSource(ref *core.SecretRef) bool {
return ref != nil && core.ValidSecretSources[ref.Source]
} Try / catch
secret, err := core.ResolveSecretInput(input, kc)
if err != nil {
if strings.HasPrefix(err.Error(), "unknown secret source:") {
// migrate the ref to file/keychain before retrying
}
return err
} Prevention
- Only emit {source: file} or {source: keychain} refs - no custom sources.
- Watch case sensitivity: Keychain and File are invalid.
- When migrating configs between environments, convert unsupported sources to file refs first.
- Diff hand-edited config.json against a known-good example to catch source typos.
When it happens
Trigger: Calling ResolveSecretInput (via authLogoutRun or ResolveConfigFromMulti) with a secret stored as {"source":"<other>","id":"..."} where source is not file or keychain - e.g. env, vault, a typo like files, or wrong casing like Keychain.
Common situations: Hand-editing config.json with an unsupported source such as environment or vault; copying configs between CLI versions that supported different source sets; case-sensitivity mistakes.
Related errors
- appSecret must be a string or {source, id} object
- Invalid column: {column!r}
- Invalid column index: {index}
- anchor outside sheet: {position!r}
- Missing row_count/column_count for sheet {sheet_title(sheet)
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/b2439e3857e10276.
Report an issue: GitHub.