tsenart/vegeta · error

bad header: %s

Error message

bad header: %s

What it means

Returned when a header line in the targets file has no ':' separator, so it cannot be split into key/value. The parser requires header lines of the form "Key: Value".

Source

Thrown at lib/targets.go:320

		tgt.URL = tokens[1]
		line = strings.TrimSpace(sc.Peek())
		if line == "" || startsWithHTTPMethod(line) {
			return nil
		}
		for sc.Scan() {
			if line = strings.TrimSpace(sc.Text()); line == "" {
				break
			} else if strings.HasPrefix(line, "#") {
				continue
			} else if strings.HasPrefix(line, "@") {
				if tgt.Body, err = os.ReadFile(line[1:]); err != nil {
					return fmt.Errorf("bad body: %w", err)
				}
				break
			}
			tokens = strings.SplitN(line, ":", 2)
			if len(tokens) < 2 {
				return fmt.Errorf("bad header: %s", line)
			}
			for i := range tokens {
				if tokens[i] = strings.TrimSpace(tokens[i]); tokens[i] == "" {
					return fmt.Errorf("bad header: %s", line)
				}
			}
			// Add key/value directly to the http.Header (map[string][]string).
			// http.Header.Add() canonicalizes keys but vegeta is used
			// to test systems that require case-sensitive headers.
			tgt.Header[tokens[0]] = append(tgt.Header[tokens[0]], tokens[1])
		}
		if err = sc.Err(); err != nil {
			return ErrNoTargets
		}
		return nil
	}
}

View on GitHub (pinned to cf58112690)

Solutions

  1. Format every header line as "Key: Value" with a colon separating them.
  2. Remove stray lines (or prefix with '#') that are not method/URL, header, body '@' line, or blank.
  3. Check the offending line text in the error and add the missing colon.
  4. Avoid pasting curl command syntax directly into targets files.

Example fix

// before
GET http://api/
Authorization Bearer xyz
// after
GET http://api/
Authorization: Bearer xyz
Defensive patterns

Strategy: validation

Validate before calling

func validHeaderLine(line string) bool {
    return strings.Contains(line, ":") &&
        strings.TrimSpace(strings.SplitN(line, ":", 2)[0]) != ""
}

Try / catch

if _, err := vegeta.NewTargets(r); err != nil {
    if strings.Contains(err.Error(), "bad header:") {
        return fmt.Errorf("header lines need 'Key: Value' form: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: A continuation line in a targets block that lacks a colon, e.g. "Authorization" alone, or a value that accidentally wrapped onto its own line without "Key:".

Common situations: Copy-pasted headers losing the colon, curl -H style flags pasted verbatim ("-H 'X: Y'"), or JSON-ish lines mistakenly included in the target block.

Related errors


AI-assisted analysis of tsenart/vegeta@cf58112690 (2026-08-31). Data as JSON: /api/errors/30c9f97d321c0507. Report an issue: GitHub.