grafana/k6 · error

parsing %s: %w

Error message

parsing %s: %w

What it means

Wraps any failure from parsing the K6_BROWSER_SCREENSHOTS_OUTPUT environment variable (file_persister.go:30). When this env var is set, the k6 browser module builds a remote screenshot persister by parsing a comma-separated k=v list; if the value violates the expected grammar, module initialization fails with this error and the browser test does not start.

Source

Thrown at internal/js/modules/k6/browser/browser/file_persister.go:30

type presignedURLConfig struct {
	getterURL string
	headers   map[string]string
	basePath  string
}

// newScreenshotPersister will return either a persister that persists file to the local
// disk or uploads the files to a remote location. This decision depends on whether
// the K6_BROWSER_SCREENSHOTS_OUTPUT env var is setup with the correct configs.
func newScreenshotPersister(envLookup env.LookupFunc) (filePersister, error) {
	envVar, ok := envLookup(env.ScreenshotsOutput)
	if !ok || envVar == "" {
		return &storage.LocalFilePersister{}, nil
	}

	popts, err := parsePresignedURLEnvVar(envVar)
	if err != nil {
		return nil, fmt.Errorf("parsing %s: %w", env.ScreenshotsOutput, err)
	}

	return storage.NewRemoteFilePersister(popts.getterURL, popts.headers, popts.basePath), nil
}

// parsePresignedURLEnvVar will parse a value such as:
// url=https://127.0.0.1/,basePath=/screenshots,header.1=a,header.2=b
// and return them.
//

func parsePresignedURLEnvVar(envVarValue string) (presignedURLConfig, error) {
	ss := strings.Split(envVarValue, ",")

	presignedURL := presignedURLConfig{
		headers: make(map[string]string),
	}
	for _, s := range ss {
		// The key value pair should be of the form key=value, so split

View on GitHub (pinned to 93accf6570)

Solutions

  1. Read the wrapped cause after the colon: it is one of 'format of value must be k=v', 'format of header must be header.k=v', 'empty header key', 'invalid url', 'invalid option', or 'missing required url'
  2. Fix the value to the exact grammar: url=https://host/,basePath=/screenshots,header.Name=value (lowercase keys, one '=' per segment)
  3. If the URL must contain '=' or ',' (presigned signatures), URL-encode them as %3D and %2C or move them into header.* entries
  4. Unset K6_BROWSER_SCREENSHOTS_OUTPUT entirely to fall back to local disk persistence and confirm the rest of the test works
  5. Re-run k6 after each change; the error appears at browser module startup, before any test code executes

Example fix

# before
export K6_BROWSER_SCREENSHOTS_OUTPUT="basepath=/screensots"
# after
export K6_BROWSER_SCREENSHOTS_OUTPUT="url=https://uploads.example.com/,basePath=/screenshots,header.Authorization=Bearer%20tok"
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# pre-flight check before `k6 run`
v="${K6_BROWSER_SCREENSHOTS_OUTPUT:?unset}"
url_seen=0
IFS=',' read -ra segs <<< "$v"
for s in "${segs[@]}"; do
  k="${s%%=*}"
  case "$k" in
    url) url_seen=1 ;;
    basePath|header.*.[^.]*) : ;;
    *) echo "invalid option: $k" >&2; exit 1 ;;
  esac
  [ "$(awk -F= '{print NF}' <<< "$s")" -eq 2 ] || { echo "segment must be k=v: $s" >&2; exit 1; }
done
[ "$url_seen" -eq 1 ] || { echo "missing required url" >&2; exit 1; }

Prevention

When it happens

Trigger: Running a browser test with K6_BROWSER_SCREENSHOTS_OUTPUT set to a malformed value, e.g. 'basepath=/shots' (missing url=), 'url' (no =), 'url=https://h/?s=1' (extra = in query), or an unknown key. Any of the inner errors (421-425, 'missing required url') is re-wrapped as 'parsing K6_BROWSER_SCREENSHOTS_OUTPUT: ...'.

Common situations: Teams wiring screenshot upload to presigned S3/GCS endpoints; CI pipelines injecting the env var with quoting or escaping mistakes; values pasted from cloud consoles containing '=' or ',' in query strings; typo'd keys like 'URL=' or 'headers.1=' after renaming from an older k6 version.

Related errors


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