{"record":{"id":"1a0bfcefc86aedf6","repo":"larksuite/cli","slug":"appsecret-must-be-a-string-or-source-id-object","errorCode":null,"errorMessage":"appSecret must be a string or {source, id} object","messagePattern":"appSecret must be a string or (.+?) object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/core/secret.go","lineNumber":76,"sourceCode":"}\n\n// UnmarshalJSON deserializes SecretInput from either a JSON string or a SecretRef object.\nfunc (s *SecretInput) UnmarshalJSON(data []byte) error {\n\t// Try string first\n\tvar plain string\n\tif err := json.Unmarshal(data, &plain); err == nil {\n\t\ts.Plain = plain\n\t\ts.Ref = nil\n\t\treturn nil\n\t}\n\t// Try SecretRef object\n\tvar ref SecretRef\n\tif err := json.Unmarshal(data, &ref); err == nil && isValidSource(ref.Source) && ref.ID != \"\" {\n\t\ts.Ref = &ref\n\t\ts.Plain = \"\"\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"appSecret must be a string or {source, id} object\")\n}\n\n// ValidSecretSources is the set of recognized SecretRef sources.\nvar ValidSecretSources = map[string]bool{\n\t\"file\": true, \"keychain\": true,\n}\n\nfunc isValidSource(source string) bool {\n\treturn ValidSecretSources[source]\n}\n","sourceCodeStart":58,"sourceCodeEnd":87,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/core/secret.go#L58-L87","documentation":"The appSecret field in config.json accepts either a plain string or an object of shape {\"source\": \"file\"|\"keychain\", \"id\": \"...\"}. SecretInput.UnmarshalJSON returns this error when the JSON value is neither a valid SecretRef (source not in ValidSecretSources or empty id) nor a plain string. It is a config schema validation error raised during unmarshalling.","triggerScenarios":"Unmarshalling config.json where appSecret is a number, boolean, array, or null; or an object whose source is not exactly file or keychain, or whose id is an empty string.","commonSituations":"Hand-editing config.json and writing appSecret as a number or {\"source\": \"env\"}; copying a secret-ref example but leaving \"id\": \"\"; a converter producing a non-string type for the secret field.","solutions":["Change appSecret to a plain JSON string: \"appSecret\": \"your-secret\".","Or use a valid reference object: {\"source\": \"file\", \"id\": \"/path/to/secret\"} or {\"source\": \"keychain\", \"id\": \"<account-key>\"}.","Ensure source is exactly file or keychain (case-sensitive) and id is a non-empty string.","Run the CLI's config init / auth login to let the tool write a correctly shaped secret."],"exampleFix":"// before (config.json)\n\"appSecret\": {\"source\": \"env\", \"id\": \"MY_SECRET\"}\n// after\n\"appSecret\": {\"source\": \"file\", \"id\": \"/home/me/.lark/secret.txt\"}","handlingStrategy":"validation","validationCode":"func validateAppSecret(v json.RawMessage) error {\n\tvar s string\n\tif json.Unmarshal(v, &s) == nil && s != \"\" {\n\t\treturn nil\n\t}\n\tvar ref struct {\n\t\tSource string `json:\"source\"`\n\t\tID     string `json:\"id\"`\n\t}\n\tif json.Unmarshal(v, &ref) == nil && core.ValidSecretSources[ref.Source] && ref.ID != \"\" {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"appSecret must be a string or {source: file|keychain, id: non-empty}\")\n}","typeGuard":"func isStringOrSecretRef(v json.RawMessage) bool {\n\tvar s string\n\tif json.Unmarshal(v, &s) == nil {\n\t\treturn true\n\t}\n\tvar ref core.SecretRef\n\treturn json.Unmarshal(v, &ref) == nil && core.ValidSecretSources[ref.Source] && ref.ID != \"\"\n}","tryCatchPattern":"var cfg Config\nif err := json.Unmarshal(data, &cfg); err != nil {\n\tif strings.Contains(err.Error(), \"appSecret must be\") {\n\t\t// fix the appSecret field shape in config.json\n\t}\n\treturn err\n}","preventionTips":["Only use source file or keychain in secret references - the set is case-sensitive.","Never leave the ref object's id empty when converting a plain secret to a reference.","Use schema/--help output to confirm accepted appSecret shapes before hand-editing.","Always quote the secret string; never store it as a number or bare token."],"tags":["config","json","validation","secret"],"backgroundTag":"invalid-secret-config","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"}