grafana/k6 · error

invalid environment variable name

Error message

invalid environment variable name '%s'

What it means

Every --env/-e entry is split on the first '=' and the key must match ^[a-zA-Z_][a-zA-Z0-9_]*$: ASCII letter or underscore first, then letters, digits, or underscores. Keys with dashes, dots, spaces, a leading digit, or an empty key ('=value') are rejected at startup. This keeps user env vars safely exposable to both the JS runtime and the OS.

Solutions

  1. Rename the key to use underscores: -e MY_VAR=1
  2. If the odd name is mandatory, set it as a real environment variable for the process instead of using -e
  3. Transform keys programmatically when generating flags: key=${key//[-.]/_}

Example fix

# before
k6 run -e "MY-VAR=1" script.js

# after
k6 run -e "MY_VAR=1" script.js
Defensive patterns

Strategy: validation

Validate before calling

# validate every -e key against k6's rule before running
valid_k6_env_key() { [[ "$1" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; }
for kv in "MY-VAR=1" "ok_var=2"; do
  key="${kv%%=*}"
  valid_k6_env_key "$key" || { echo "invalid env var name '$key'" >&2; exit 1; }
done
k6 run -e "MY_VAR=1" -e ok_var=2 script.js

Type guard

valid_k6_env_key() { [[ "$1" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] && return 0 || return 1; }
# usage: valid_k6_env_key "MY_VAR" && k6 run -e "MY_VAR=1" script.js

Prevention

When it happens

Trigger: k6 run -e 'MY-VAR=1' script.js (dash); -e '2FA=x' (leading digit); -e 'my.var=1' (dot); -e '=value' (empty key); values themselves are unrestricted — only the key is validated.

Common situations: Passing CI variable names (MY-APP-KEY, BUILD.ID) verbatim; copying names from other tools' env conventions; shell scripts building -e flags from filenames with dashes.

Related errors


AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18). Data as JSON: /api/errors/4766f5e9dadcdf81. Report an issue: GitHub.

Appendix: source

Thrown at internal/cmd/runtime_options.go:69

	environment map[string]string,
) (lib.RuntimeOptions, error) {
	// TODO: refactor with composable helpers as a part of #883, to reduce copy-paste
	// TODO: get these options out of the JSON config file as well?
	opts, err := populateRuntimeOptionsFromEnv(runtimeOptionsFromFlags(flags), environment)
	if err != nil {
		return opts, err
	}

	// Set/overwrite environment variables with custom user-supplied values
	envVars, err := flags.GetStringArray("env")
	if err != nil {
		return opts, err
	}
	for _, kv := range envVars {
		k, v := state.ParseEnvKeyValue(kv)
		// Allow only alphanumeric ASCII variable names for now
		if !userEnvVarName.MatchString(k) {
			return opts, fmt.Errorf("invalid environment variable name '%s'", k)
		}
		opts.Env[k] = v
	}

	return opts, nil
}

func runtimeOptionsFromFlags(flags *pflag.FlagSet) lib.RuntimeOptions {
	opts := lib.RuntimeOptions{
		TestType:                  getNullString(flags, "type"),
		IncludeSystemEnvVars:      getNullBool(flags, "include-system-env-vars"),
		CompatibilityMode:         getNullString(flags, "compatibility-mode"),
		NoThresholds:              getNullBool(flags, "no-thresholds"),
		SummaryMode:               getNullString(flags, "summary-mode"),
		SummaryExport:             getNullString(flags, "summary-export"),
		NewMachineReadableSummary: getNullBool(flags, "new-machine-readable-summary"),
		TracesOutput:              getNullString(flags, "traces-output"),
		Env:                       make(map[string]string),

View on GitHub (pinned to 01ffac6f24)