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

  1. Put the literal {key} placeholder where the secret name belongs: K6_SECRET_SOURCE_URL_URL_TEMPLATE='https://vault.example.com/api/secrets/{key}'
  2. Verify before running k6: echo "$K6_SECRET_SOURCE_URL_URL_TEMPLATE" | grep -q '{key}' || echo 'missing {key}'
  3. 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

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


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/ba174b210aab1d08. Report an issue: GitHub.