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
- Re-copy the key ensuring nothing follows the 64-char secret.
- In config files, quote the whole key exactly once and keep it on one line.
- 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
- Check for characters accidentally appended (quotes, commas, second keys) when embedding in JSON/YAML.
- Trim whitespace once, then enforce exact length.
- Prefer dedicated secret fields over free-text config blocks for keys.
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
- %w: key too short, expected at least %d chars after prefix,
- %w: expected separator '-' at position %d, got '%c'
- %w: prefix contains invalid characters (expected base64 URL-
- %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/bda0527ecb1e25f0.
Report an issue: GitHub.