wavetermdev/waveterm · error
secret not found: %s
Error message
secret not found: %s
What it means
After a successful GetSecretsCommand RPC, the command looks up the requested name in the returned map; if the key is absent it reports the secret does not exist. This is a normal not-found condition, not an RPC failure — the daemon responded but has no secret stored under that name.
Source
Thrown at cmd/wsh/cmd/wshcmd-secret.go:95
func secretGetRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("secret", rtnErr == nil)
}()
name := args[0]
if !secretNameRegex.MatchString(name) {
return fmt.Errorf("invalid secret name: must start with a letter and contain only letters, numbers, and underscores")
}
resp, err := wshclient.GetSecretsCommand(RpcClient, []string{name}, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
return fmt.Errorf("getting secret: %w", err)
}
value, ok := resp[name]
if !ok {
return fmt.Errorf("secret not found: %s", name)
}
WriteStdout("%s\n", value)
return nil
}
func secretSetRun(cmd *cobra.Command, args []string) (rtnErr error) {
defer func() {
sendActivity("secret", rtnErr == nil)
}()
parts := strings.SplitN(args[0], "=", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid format: expected [name]=[value]")
}
name := parts[0]
value := parts[1]View on GitHub (pinned to a4447c1563)
Solutions
- Run `wsh secret list` to see the exact stored names and correct the spelling/case.
- Set the secret first with `wsh secret set NAME=VALUE`, then get it.
- If you expect the secret from another machine, remember the secret store is per-machine (keyring-backed); set it locally or sync it explicitly.
- If the name was set via wconfig secrets files, verify the file was loaded by the daemon and the name matches the store's naming rules.
Example fix
// before value=$(wsh secret get DB_PASS) // after wsh secret list # confirm exact name value=$(wsh secret get DB_PASSWORD)
Defensive patterns
Strategy: validation
Validate before calling
names, _ := wshclient.GetSecretsNamesCommand(RpcClient, &wshrpc.RpcOpts{Timeout: 2000})
if !slices.Contains(names, name) {
return fmt.Errorf("secret %q does not exist; available: %v", name, names)
} Type guard
func secretExists(resp map[string]string, name string) bool {
_, ok := resp[name]
return ok
} Try / catch
value, ok := resp[name]
if !ok {
return fmt.Errorf("secret not found: %s (run 'wsh secret list' to see stored names)", name)
} Prevention
- List secrets before getting to verify exact spelling and casing
- Treat names as case-sensitive; standardize on a naming convention
- Remember the store is per-machine — set secrets on the machine where you read them
- Handle not-found explicitly in scripts instead of assuming the secret exists
When it happens
Trigger: Running `wsh secret get NAME` where NAME passes the name regex and the RPC succeeds, but no secret was ever set under NAME (or it was deleted), e.g. `wsh secret get db_password` when only `dbPassword` exists.
Common situations: Typo'd or case-mismatched names (Secrets are case-sensitive); secrets set on a different machine/profile than the one queried; secret deleted via the Wave secrets UI; fresh environment where setup scripts never ran.
Related errors
- deleting secret: %w
- no files or message provided
- too many files (maximum %d files allowed)
- stdin (-) can only be used once
- reading from stdin: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/1c5539ad46f36ac0.
Report an issue: GitHub.