{"record":{"id":"8748eef98b385fc7","repo":"grafana/k6","slug":"urltemplate-must-be-an-absolute-url-with-a-scheme","errorCode":null,"errorMessage":"urlTemplate must be an absolute URL with a scheme (e.g., https://...)","messagePattern":"urlTemplate must be an absolute URL with a scheme \\(e\\.g\\., https://\\.\\.\\.\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/secretsource/url/url.go","lineNumber":537,"sourceCode":"\tif urlTemplate == \"\" {\n\t\treturn errMissingURLTemplate\n\t}\n\n\t// Require {key} placeholder to differentiate between secrets\n\tif !strings.Contains(urlTemplate, \"{key}\") {\n\t\treturn errors.New(\"urlTemplate must contain {key} placeholder\")\n\t}\n\n\t// Replace {key} placeholder with a dummy value for validation\n\ttestURL := strings.ReplaceAll(urlTemplate, \"{key}\", \"test\")\n\tparsedURL, err := url.Parse(testURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"urlTemplate is not a valid URL: %w\", err)\n\t}\n\n\t// Require absolute URL with scheme\n\tif parsedURL.Scheme == \"\" {\n\t\treturn errors.New(\"urlTemplate must be an absolute URL with a scheme (e.g., https://...)\")\n\t}\n\n\treturn nil\n}\n\nfunc getConfig(arg string, fs fsext.Fs, env map[string]string) (extConfig, error) {\n\t// Start with defaults\n\tconfig := newConfig()\n\n\t// Apply environment variables\n\t// Order of precedence (lowest to highest):\n\t// 1. Defaults\n\t// 2. Environment variables\n\t// 3. Config file (if specified)\n\t// 4. Inline CLI flags\n\tenvCfg, err := parseEnvConfig(env)\n\tif err != nil {\n\t\treturn extConfig{}, err","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/secretsource/url/url.go#L519-L555","documentation":"After substituting a dummy value for '{key}', k6 parses the template with url.Parse() and requires a non-empty Scheme. A template that parses successfully but has no scheme (a relative URL such as 'vault.example.com/{key}') cannot be fetched by the HTTP client, so validateURLTemplate() rejects it. Note that url.Parse rarely returns an error, so this scheme check is the main guard against non-absolute templates.","triggerScenarios":"Setting urlTemplate to a host/path without a protocol, e.g. 'vault.example.com/secrets/{key}' or '/secrets/{key}', via env var, inline arg, or JSON config file.","commonSituations":"Omitting the 'https://' prefix by accident; using a template built from a host variable where the scheme was expected to be implicit; copy-pasting a path-only endpoint from API docs.","solutions":["Prefix the template with a scheme: 'https://vault.example.com/secrets/{key}'","If building the template from variables, assert it matches /^https?:\\/\\// before starting k6","Check for typos like 'httpss://' or a leading space that breaks scheme parsing"],"exampleFix":"# before\nK6_SECRET_SOURCE_URL_URL_TEMPLATE='vault.example.com/secrets/{key}'\n\n# after\nK6_SECRET_SOURCE_URL_URL_TEMPLATE='https://vault.example.com/secrets/{key}'","handlingStrategy":"validation","validationCode":"const tpl = process.env.K6_SECRET_SOURCE_URL_URL_TEMPLATE ?? '';\nif (!/^https?:\\/\\/.*\\{key\\}/.test(tpl)) {\n  throw new Error(`bad urlTemplate: ${tpl}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write secret URLs with an explicit scheme","Unit-test template builders against /^https?:\\/\\//","Reject path-only templates in config review"],"tags":["config","secrets","url","validation","startup"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}