{"record":{"id":"4509e33d9c1aea74","repo":"larksuite/cli","slug":"exec-provider-value-for-id-q-is-not-a-string","errorCode":null,"errorMessage":"exec provider value for id %q is not a string","messagePattern":"exec provider value for id %q is not a string","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/binding/secret_resolve_exec.go","lineNumber":240,"sourceCode":"\tif resp.Values == nil {\n\t\treturn \"\", fmt.Errorf(\"exec provider response missing 'values'\")\n\t}\n\tvalue, ok := resp.Values[refID]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"exec provider response missing id %q\", refID)\n\t}\n\n\tif str, ok := value.(string); ok {\n\t\treturn str, nil\n\t}\n\tif !jsonOnly {\n\t\tdata, err := json.Marshal(value)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"exec provider value for id %q is not JSON-serializable: %w\", refID, err)\n\t\t}\n\t\treturn string(data), nil\n\t}\n\treturn \"\", fmt.Errorf(\"exec provider value for id %q is not a string\", refID)\n}\n","sourceCodeStart":222,"sourceCodeEnd":242,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/binding/secret_resolve_exec.go#L222-L242","documentation":"The exec secret provider ran an external command and received a JSON value for the requested ref id, but that value is neither a plain string nor JSON-serializable data the resolver accepts. The library only treats string values (or values it can marshal to JSON) as valid secrets, so any other shape is rejected to avoid silently injecting a non-string secret into configuration. This guards the contract that resolved secrets are strings.","triggerScenarios":"Calling resolveSecretRef with a {source:\"exec\"} SecretRef where the exec provider's command outputs JSON whose value for ref.ID is an object, array, number, or boolean that fails the string/marshalable check in extractExecSecret (internal/binding/secret_resolve_exec.go:240).","commonSituations":"The external secret command (e.g. a vault CLI or script) returns a structured JSON object like {\"password\":{\"value\":\"x\"}} instead of a flat string for the requested id; a script was updated to emit nested config; or the ref id points at a non-string JSON field such as a number (port, TTL).","solutions":["Change the exec command (or add a wrapper like jq -r) so it outputs a plain string for that ref id, e.g. `jq -r '.password.value'`.","Update the SecretRef id to point at the JSON key that actually holds the string secret.","If a structured value is intentional, ensure it is JSON-serializable at the provider so the marshal path in extractExecSecret succeeds instead of reaching the non-string branch."],"exampleFix":"// before: exec command prints nested JSON\n{\"db\": {\"password\": \"s3cret\"}}\n// after: exec command prints the string value\njq -r '.db.password' | your-secret-command","handlingStrategy":"validation","validationCode":"out, err := runExecProvider(cmd) // your wrapper capturing stdout\nvar v any\nif err := json.Unmarshal(out, &v); err == nil {\n    if _, ok := v.(string); !ok {\n        return fmt.Errorf(\"exec provider must output a string, got %T\", v)\n    }\n}","typeGuard":"func isStringSecret(v any) bool { _, ok := v.(string); return ok }","tryCatchPattern":"secret, err := resolveSecretRef(ctx, execRef)\nif err != nil {\n    if strings.Contains(err.Error(), \"is not a string\") {\n        // inspect provider output shape and fix the ref id or command\n    }\n    return err\n}","preventionTips":["Make exec provider commands emit exactly one plain string (use jq -r for JSON sources).","Test each exec provider command's output shape alongside the binding config.","Keep one ref id per output key and never point ids at nested objects."],"tags":["secrets","exec-provider","type-mismatch"],"backgroundTag":"secret-provider-non-string-value","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"}