{"record":{"id":"22c23038f4f9c594","repo":"wavetermdev/waveterm","slug":"error-setting-secret-q-w","errorCode":null,"errorMessage":"error setting secret %q: %w","messagePattern":"error setting secret %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshrpc/wshserver/wshserver.go","lineNumber":1507,"sourceCode":"func (ws *WshServer) GetSecretsNamesCommand(ctx context.Context) ([]string, error) {\n\tnames, err := secretstore.GetSecretNames()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting secret names: %w\", err)\n\t}\n\treturn names, nil\n}\n\nfunc (ws *WshServer) SetSecretsCommand(ctx context.Context, secrets map[string]*string) error {\n\tfor name, value := range secrets {\n\t\tif value == nil {\n\t\t\terr := secretstore.DeleteSecret(name)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting secret %q: %w\", name, err)\n\t\t\t}\n\t\t} else {\n\t\t\terr := secretstore.SetSecret(name, *value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting secret %q: %w\", name, err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (ws *WshServer) GetSecretsLinuxStorageBackendCommand(ctx context.Context) (string, error) {\n\tbackend, err := secretstore.GetLinuxStorageBackend()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error getting linux storage backend: %w\", err)\n\t}\n\treturn backend, nil\n}\n\nfunc (ws *WshServer) JobCmdExitedCommand(ctx context.Context, data wshrpc.CommandJobCmdExitedData) error {\n\treturn jobcontroller.HandleCmdJobExited(ctx, data.JobId, data)\n}\n","sourceCodeStart":1489,"sourceCodeEnd":1525,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshrpc/wshserver/wshserver.go#L1489-L1525","documentation":"SetSecretsCommand calls secretstore.SetSecret for non-nil values to store or update a secret. A backend write failure is wrapped as \"error setting secret %q\". Because iteration order over the map is not deterministic, a failure aborts remaining entries and which secrets were applied may vary between runs.","triggerScenarios":"SetSecretsCommand with {name: &value} while the secret backend rejects the write — locked keychain, full/immutable backend storage, item size limits, or missing secret service on Linux.","commonSituations":"Storing tokens over a remote/headless session without a keyring; keychain prompting denied by the user; read-only fallback storage file; very large secret values exceeding backend limits.","solutions":["Read the wrapped cause to identify the backend failure mode.","Unlock the keychain / start the secret service and retry.","Apply secrets one at a time so partial success is deterministic.","Reduce secret size or check backend storage permissions if limits/permissions are implicated."],"exampleFix":"// before\nwshclient.SetSecretsCommand(ctx, map[string]*string{\"a\": &a, \"b\": &b}) // fails partway, nondeterministic\n// after\nfor name, val := range secrets {\n    if err := wshclient.SetSecretsCommand(ctx, map[string]*string{name: val}); err != nil {\n        return fmt.Errorf(\"failed on %q: %w\", name, err)\n    }\n}","handlingStrategy":"validation","validationCode":"const maxSecretLen = 8 * 1024 // conservative backend limit\nif value != nil && len(*value) > maxSecretLen {\n    return fmt.Errorf(\"secret %q too large for backend storage\", name)\n}","typeGuard":null,"tryCatchPattern":"err := wshclient.SetSecretsCommand(ctx, map[string]*string{name: &value})\nif err != nil && strings.Contains(err.Error(), \"error setting secret\") {\n    // prompt user to unlock keychain or fall back to prompt-on-use instead of storing\n}","preventionTips":["Write secrets one at a time; map iteration order makes batched writes non-deterministic on failure.","Keep secret values small; large values may exceed backend limits.","Ensure an unlocked keyring/secret service exists before automated writes.","Handle user-denied keychain prompts (macOS) as a retry-able condition."],"tags":["secrets","keychain","rpc"],"backgroundTag":"keychain-write-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}