wavetermdev/waveterm · error
invalid secret name: must start with a letter and contain on
Error message
invalid secret name: must start with a letter and contain only letters, numbers, and underscores
What it means
The `wsh secret get` command validates the secret name locally against secretNameRegex (`^[A-Za-z][A-Za-z0-9_]*$`) before making any RPC call, mirroring the server-side validation in pkg/wconfig/secretstore.go. If the name contains hyphens, dots, leading digits, or other symbols, the command fails fast with this error without contacting the daemon. It exists to keep client and server naming rules consistent and avoid wasted RPC round-trips.
Source
Thrown at cmd/wsh/cmd/wshcmd-secret.go:85
func init() {
secretUiCmd.Flags().BoolVarP(&secretUiMagnified, "magnified", "m", false, "open secrets UI in magnified mode")
rootCmd.AddCommand(secretCmd)
secretCmd.AddCommand(secretGetCmd)
secretCmd.AddCommand(secretSetCmd)
secretCmd.AddCommand(secretListCmd)
secretCmd.AddCommand(secretDeleteCmd)
secretCmd.AddCommand(secretUiCmd)
}
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() {View on GitHub (pinned to a4447c1563)
Solutions
- Rename the argument to match ^[A-Za-z][A-Za-z0-9_]*$: start with a letter, use only letters, digits, underscores (e.g. api_key instead of api-key).
- Run `wsh secret list` to see valid existing secret names and pick the correct one.
- If the secret must be stored under a hyphenated external name, store it under a compliant alias (e.g. `wsh secret set api_key=...`) and reference that instead.
- If you believe a valid name is rejected, check the regex in cmd/wsh/cmd/wshcmd-secret.go:18 and pkg/wconfig/secretstore.go for version mismatches between wsh CLI and daemon.
Example fix
// before wsh secret get api-key // after wsh secret get api_key
Defensive patterns
Strategy: validation
Validate before calling
var secretNameRe = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_]*$`)
if !secretNameRe.MatchString(name) {
return fmt.Errorf("name %q must match ^[A-Za-z][A-Za-z0-9_]*$", name)
} Type guard
func isValidSecretName(s string) bool {
return regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_]*$`).MatchString(s)
} Prevention
- Normalize external names (kebab/dotted) to snake_case before calling wsh secret commands
- Keep a single shared regex constant in sync with pkg/wconfig/secretstore.go
- Validate names at script start and fail fast with a clear message
- Prefer listing (`wsh secret list`) to confirm exact names before get/delete
When it happens
Trigger: Running `wsh secret get` with a name violating the regex: e.g. `wsh secret get api-key` (hyphen), `wsh secret get my.secret` (dot), `wsh secret get 1token` (leading digit), or a name with spaces/special characters.
Common situations: Secrets were set with different naming conventions (kebab-case from CI tools like AWS/GitHub, e.g. SECRET-API-KEY); users copy environment-variable-like names with dots (e.g. db.host); automation scripts pass names derived from file names or domains.
Related errors
- badge oref must be a block or tab (got %q)
- unknown --view %q; try one of: term, web, preview, edit, sys
- --workspace and --window are mutually exclusive; specify onl
- cannot parse connection name: %w
- --conn parameter is required
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/5cd0f764ab3d290b.
Report an issue: GitHub.