{"record":{"id":"3f24a8d1d9b98d5c","repo":"grafana/k6","slug":"couldn-t-parse-secret-source-configuration-q","errorCode":null,"errorMessage":"couldn't parse secret source configuration %q","messagePattern":"couldn't parse secret source configuration %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/root.go","lineNumber":504,"sourceCode":"\t\tpcancel()\n\t})\n}\n\n//nolint:gocognit\nfunc createSecretSources(gs *state.GlobalState) (map[string]secretsource.Source, error) {\n\tbaseParams := secretsource.Params{\n\t\tLogger:      gs.Logger,\n\t\tEnvironment: gs.Env,\n\t\tFS:          gs.FS,\n\t\tUsage:       gs.Usage,\n\t}\n\n\tresult := make(map[string]secretsource.Source)\n\tfor _, line := range gs.Flags.SecretSource {\n\t\tt, config, ok := strings.Cut(line, \"=\")\n\t\tif !ok {\n\t\t\tif strings.TrimSpace(line) == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"couldn't parse secret source configuration %q\", line)\n\t\t\t}\n\t\t\t// Allow any non-empty source type without explicit config — it will use\n\t\t\t// environment variables and built-in defaults.\n\t\t\tt = line\n\t\t\tconfig = \"\"\n\t\t}\n\t\tsecretSources := ext.Get(ext.SecretSourceExtension)\n\t\tfound, ok := secretSources[t]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"no secret source for type %q for configuration %q\", t, line)\n\t\t}\n\t\tc := found.Module.(secretsource.Constructor) //nolint:forcetypeassert\n\t\tparams := baseParams\n\t\tname, isDefault, config := extractNameAndDefault(config)\n\t\tif name == \"\" {\n\t\t\t// Default the name to the source type to avoid an empty-string key.\n\t\t\tname = t\n\t\t}","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/grafana/k6/blob/8d06114777191d21ef885d05c5f8aa9e1ed838ae/internal/cmd/root.go#L486-L522","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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"],"exampleFix":"# before\nk6 run --secret-source= script.js\n\n# after\nk6 run --secret-source=file=secrets.txt script.js","handlingStrategy":"validation","validationCode":"# when building --secret-source flags dynamically, drop empty entries\nSECRET_FLAGS=()\nfor src in ${SECRET_SOURCES}; do\n  [ -n \"$(printf '%s' \"$src\" | tr -d '[:space:]')\" ] && SECRET_FLAGS+=(--secret-source=\"$src\")\ndone\nk6 run \"${SECRET_FLAGS[@]}\" script.js","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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 '='"],"tags":["k6","secrets","secret-source","cli-flag","config"],"backgroundTag":"invalid-cli-flag-value","analyzedSha":"8d06114777191d21ef885d05c5f8aa9e1ed838ae","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}