grafana/k6 · error
couldn't parse secret source configuration
Error message
couldn't parse secret source configuration %q
What it means
Each --secret-source entry (or K6_SECRET_SOURCE value) is first split on the first '='. If an entry contains no '=' AND is empty or whitespace-only, there is no source type to look up, so k6 rejects the whole secret configuration at startup. A non-empty type-only entry like 'file' is valid and uses built-in defaults.
Solutions
- Remove the empty --secret-source entry from the command or CI environment
- Give the flag a real value: --secret-source=file (defaults) or --secret-source=file=path/to/secrets
- If building flags dynamically, emit the flag only when the value is non-empty
Example fix
# before k6 run --secret-source= script.js # after k6 run --secret-source=file=secrets.txt script.js
Defensive patterns
Strategy: validation
Validate before calling
# when building --secret-source flags dynamically, drop empty entries
SECRET_FLAGS=()
for src in ${SECRET_SOURCES}; do
[ -n "$(printf '%s' "$src" | tr -d '[:space:]')" ] && SECRET_FLAGS+=(--secret-source="$src")
done
k6 run "${SECRET_FLAGS[@]}" script.js Prevention
- Quote and check every --secret-source entry when generating commands from templates
- Fail fast in CI if a secrets variable is empty and secrets are required, instead of passing an empty flag
- Prefer type-only (file) or type=config (file=secrets.txt) forms; never emit a bare '='
When it happens
Trigger: `k6 run --secret-source= script.js` (empty flag value), `--secret-source " "`, or a shell loop/CI template that emits `--secret-source=` when its input variable is blank.
Common situations: Dynamically built command lines that append --secret-source=$VAR with VAR unset; YAML/CI matrices leaving the secret-source variable empty; copy-paste leaving a stray empty flag.
Related errors
- can't have two secret sources that are default ones, second…
- no secret source for type
- secret source for name
- 104
- failed to initialize cloud secret source
AI-assisted analysis of grafana/k6@8d06114777 (2026-08-18).
Data as JSON: /api/errors/3f24a8d1d9b98d5c.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cmd/root.go:504
pcancel()
})
}
//nolint:gocognit
func createSecretSources(gs *state.GlobalState) (map[string]secretsource.Source, error) {
baseParams := secretsource.Params{
Logger: gs.Logger,
Environment: gs.Env,
FS: gs.FS,
Usage: gs.Usage,
}
result := make(map[string]secretsource.Source)
for _, line := range gs.Flags.SecretSource {
t, config, ok := strings.Cut(line, "=")
if !ok {
if strings.TrimSpace(line) == "" {
return nil, fmt.Errorf("couldn't parse secret source configuration %q", line)
}
// Allow any non-empty source type without explicit config — it will use
// environment variables and built-in defaults.
t = line
config = ""
}
secretSources := ext.Get(ext.SecretSourceExtension)
found, ok := secretSources[t]
if !ok {
return nil, fmt.Errorf("no secret source for type %q for configuration %q", t, line)
}
c := found.Module.(secretsource.Constructor) //nolint:forcetypeassert
params := baseParams
name, isDefault, config := extractNameAndDefault(config)
if name == "" {
// Default the name to the source type to avoid an empty-string key.
name = t
}View on GitHub (pinned to 8d06114777)