juanfont/headscale · error · parseErr (ErrPreAuthKeyFailedToParse|ErrOAuthClientFailedToParse|ErrAccessTokenFailedToParse|ErrAPIKeyFailedToParse)
%w: prefix contains invalid characters (expected base64 URL-
Error message
%w: prefix contains invalid characters (expected base64 URL-safe: A-Za-z0-9_-)
What it means
The 12-character prefix portion of a parsed credential contains characters outside the base64 URL-safe alphabet (A-Za-z0-9_-). Current headscale generates key material as hex (a subset), so a violation means the prefix was corrupted or is not a headscale key at all. The parseErr sentinel is wrapped for classification.
Source
Thrown at hscontrol/db/preauth_keys.go:280
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(
"%w: secret contains invalid characters (expected base64 URL-safe: A-Za-z0-9_-)",
parseErr,
)
}
return prefix, secret, nil
}
// isValidBase64URLSafe reports whether s contains only base64 URL-safe
// characters (A-Za-z0-9-_). Key material is now generated as hex, a subset ofView on GitHub (pinned to 565fd254d0)
Solutions
- Confirm the key starts with the 'hskey-' scheme and was issued by this headscale instance.
- If the key passed through a URL or form, ensure it was not percent-encoded or truncated.
- Regenerate the key from the headscale CLI/API and use it directly.
Defensive patterns
Strategy: validation
Validate before calling
var base64URLSafe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
func validPrefix(p string) bool {
return len(p) == 12 && base64URLSafe.MatchString(p)
} Prevention
- Confirm the 'hskey-' scheme prefix before parsing — reject foreign keys early.
- URL-decode keys exactly once if they travel through query parameters.
- Log a SHA of rejected keys, never the key itself, for debugging.
When it happens
Trigger: Passing a non-headscale credential (e.g. a Tailscale authkey 'tskey-auth-...') into headscale's key parser, or a prefix mangled by encoding (spaces, '%', '=' from URL encoding).
Common situations: Mixing up headscale and Tailscale keys in configs; URL-encoding or HTML-entity corruption when keys travel through web forms or query parameters.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- %w: key too short, expected at least %d chars after prefix,
- %w: expected separator '-' at position %d, got '%c'
- %w: secret length mismatch, expected %d chars, got %d
- %w: secret contains invalid characters (expected base64 URL-
- failed to parse auth-key
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/5047e6bacc4d4041.
Report an issue: GitHub.