grafana/k6 · error
urlTemplate must contain {key} placeholder
Error message
urlTemplate must contain {key} placeholder What it means
k6's 'url' secret source fetches each secret over HTTP by substituting the secret's name into a URL template. validateURLTemplate() rejects any template that lacks the literal '{key}' placeholder, because without it every secret would resolve to the same URL and individual secrets could not be addressed. The check runs at startup inside getConfig()/validateConfig(), before any test code executes.
Source
Thrown at internal/secretsource/url/url.go:525
return extConfig{}, fmt.Errorf("failed to read config file: %w", err)
}
var fileCfg extConfig
if err := json.Unmarshal(configData, &fileCfg); err != nil {
return extConfig{}, fmt.Errorf("failed to parse JSON config: %w", err)
}
return fileCfg, nil
}
func validateURLTemplate(urlTemplate string) error {
if urlTemplate == "" {
return errMissingURLTemplate
}
// Require {key} placeholder to differentiate between secrets
if !strings.Contains(urlTemplate, "{key}") {
return errors.New("urlTemplate must contain {key} placeholder")
}
// Replace {key} placeholder with a dummy value for validation
testURL := strings.ReplaceAll(urlTemplate, "{key}", "test")
parsedURL, err := url.Parse(testURL)
if err != nil {
return fmt.Errorf("urlTemplate is not a valid URL: %w", err)
}
// Require absolute URL with scheme
if parsedURL.Scheme == "" {
return errors.New("urlTemplate must be an absolute URL with a scheme (e.g., https://...)")
}
return nil
}
func getConfig(arg string, fs fsext.Fs, env map[string]string) (extConfig, error) {View on GitHub (pinned to 93accf6570)
Solutions
- Put the literal {key} placeholder where the secret name belongs: K6_SECRET_SOURCE_URL_URL_TEMPLATE='https://vault.example.com/api/secrets/{key}'
- Verify before running k6: echo "$K6_SECRET_SOURCE_URL_URL_TEMPLATE" | grep -q '{key}' || echo 'missing {key}'
- If the backend has no per-key URL pattern, switch to a secret source that fits (file, env) instead of url
Example fix
# before
K6_SECRET_SOURCE_URL_URL_TEMPLATE='https://vault.example.com/secrets/mytoken'
# after
K6_SECRET_SOURCE_URL_URL_TEMPLATE='https://vault.example.com/secrets/{key}' Defensive patterns
Strategy: validation
Validate before calling
#!/usr/bin/env bash
tpl="$K6_SECRET_SOURCE_URL_URL_TEMPLATE"
[ -n "$tpl" ] && [[ "$tpl" == *'{key}'* ]] || { echo 'urlTemplate must contain {key}'; exit 1; } Prevention
- Keep urlTemplate values in one place (CI variable or config file) instead of duplicating them
- Add a CI lint step that greps the template for the literal {key}
- Document the placeholder convention next to the secret source setup
When it happens
Trigger: Configuring the url secret source via K6_SECRET_SOURCE_URL_URL_TEMPLATE, an inline CLI argument, or a JSON config file whose urlTemplate value has no '{key}' substring, e.g. 'https://vault.example.com/secrets/mysecret'.
Common situations: Hard-coding one secret's URL instead of templating it; copying an example that used a different placeholder name such as '{name}' or '$key'; URL-encoding the braces (%7Bkey%7D) so the literal '{key}' no longer matches.
Related errors
- urlTemplate must be an absolute URL with a scheme (e.g., htt
- timeout must be greater than 0
- requestsPerMinuteLimit must be greater than 0
- requestsBurst must be greater than 0
- maxRetries must be non-negative
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/ba174b210aab1d08.
Report an issue: GitHub.