juanfont/headscale · error · parseErr (ErrPreAuthKeyFailedToParse|ErrOAuthClientFailedToParse|ErrAccessTokenFailedToParse|ErrAPIKeyFailedToParse)

%w: secret length mismatch, expected %d chars, got %d

Error message

%w: secret length mismatch, expected %d chars, got %d

What it means

parsePrefixedKey split the string correctly at the separator, but the remaining secret is not exactly secretLen (64) characters. Since the total length minimum was already checked, this specifically fires when the string is longer than expected — extra trailing characters after a valid secret.

Source

Thrown at hscontrol/db/preauth_keys.go:270

	}

	prefix := prefixAndSecret[:prefixLen]

	// Validate separator at expected position
	if prefixAndSecret[prefixLen] != '-' {
		return "", "", fmt.Errorf(
			"%w: expected separator '-' at position %d, got '%c'",
			parseErr,
			prefixLen,
			prefixAndSecret[prefixLen],
		)
	}

	secret := prefixAndSecret[prefixLen+1:]

	// Validate secret length
	if len(secret) != secretLen {
		return "", "", fmt.Errorf(
			"%w: secret length mismatch, expected %d chars, got %d",
			parseErr,
			secretLen,
			len(secret),
		)
	}

	// Validate prefix contains only base64 URL-safe characters
	if !isValidBase64URLSafe(prefix) {
		return "", "", fmt.Errorf(
			"%w: prefix contains invalid characters (expected base64 URL-safe: A-Za-z0-9_-)",
			parseErr,
		)
	}

	// Validate secret contains only base64 URL-safe characters
	if !isValidBase64URLSafe(secret) {
		return "", "", fmt.Errorf(

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Re-copy the key ensuring nothing follows the 64-char secret.
  2. In config files, quote the whole key exactly once and keep it on one line.
  3. Add a pre-check on exact length (77 chars after the scheme prefix) before using the key.
Defensive patterns

Strategy: validation

Validate before calling

func exactKeyLength(rest string) bool {
    return len(rest) == 12+1+64 // fixed-layout format
}

Prevention

When it happens

Trigger: A key with trailing garbage: appended newline handling already done but extra characters pasted (e.g. two keys concatenated, a trailing quote or comma from JSON/YAML), or shell quoting that glued extra text onto the secret.

Common situations: Copy/paste grabbing the next line in a config file, JSON values quoted incorrectly, or scripts concatenating key + comment.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/bda0527ecb1e25f0. Report an issue: GitHub.