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

  1. 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).
  2. Run `wsh secret list` to see valid existing secret names and pick the correct one.
  3. 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.
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/5cd0f764ab3d290b. Report an issue: GitHub.