juanfont/headscale · warning
ErrUnsupportedClientVersion
ErrUnsupportedClientVersion
Error message
unsupported client version: %s (%d)
What it means
Returned during the early Noise stage when the client's declared protocol/capability version is below the minimum supported by this headscale build (isSupportedVersion check against capver data). The error names the mapped Tailscale version and raw capability number via ErrUnsupportedClientVersion.
Source
Thrown at hscontrol/noise.go:225
r.Post("/c2n", ns.NotImplementedHandler)
})
ns.httpBaseConfig = &http.Server{
Handler: r,
ReadHeaderTimeout: types.HTTPTimeout,
}
ns.http2Server = &http2.Server{}
ns.http2Server.ServeConn(
noiseConn,
&http2.ServeConnOpts{
BaseConfig: ns.httpBaseConfig,
},
)
}
func unsupportedClientError(version tailcfg.CapabilityVersion) error {
return fmt.Errorf("%w: %s (%d)", ErrUnsupportedClientVersion, capver.TailscaleVersion(version), version)
}
func (ns *noiseServer) earlyNoise(protocolVersion int, writer io.Writer) error {
if !isSupportedVersion(tailcfg.CapabilityVersion(protocolVersion)) {
return unsupportedClientError(tailcfg.CapabilityVersion(protocolVersion))
}
earlyJSON, err := json.Marshal(&tailcfg.EarlyNoise{
NodeKeyChallenge: ns.challenge.Public(),
})
if err != nil {
return err
}
// 5 bytes that won't be mistaken for an HTTP/2 frame:
// https://httpwg.org/specs/rfc7540.html#rfc.section.4.1 (Especially not
// an HTTP/2 settings frame, which isn't of type 'T')
var notH2Frame [5]byteView on GitHub (pinned to 565fd254d0)
Solutions
- Upgrade the client tailscaled to a recent stable release (check the version in the error message)
- Compare the client's capability version against hscontrol/capver data to find the minimum accepted
- If upgrading is impossible, pin an older headscale release that still supports that capability version
Defensive patterns
Strategy: validation
Validate before calling
if !isSupportedVersion(clientCapVer) {
return fmt.Errorf("client version %s (%d) is below minimum supported; upgrade tailscaled",
capver.TailscaleVersion(clientCapVer), clientCapVer)
} Type guard
func isSupportedClient(v tailcfg.CapabilityVersion) bool {
return isSupportedVersion(v)
} Prevention
- Pin client tailscaled versions at or above headscale's minimum capability version in fleet management
- Monitor for ErrUnsupportedClientVersion in logs to catch stale clients before they multiply
When it happens
Trigger: A tailscaled older than the server's minimum supported capability version connects via /ts2021; earlyNoise rejects it before any API traffic flows.
Common situations: Distro-packaged stale tailscale clients (e.g. 1.32-era) against a current headscale; embedded appliances that rarely update; after a headscale upgrade that raised the minimum capver.
Related errors
- MOCKOIDC_CLIENT_SECRET not defined
- MOCKOIDC_PORT not defined
- command aborted by user
- --name or --identifier flag is required
- ssh action: cached auth session is not an SSH-check binding
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/a937e3accdd623a6.
Report an issue: GitHub.