juanfont/headscale · error
handling register interactive: %w
Error message
handling register interactive: %w
What it means
Wraps failures of handleRegisterInteractive during interactive (browser-based) registration (hscontrol/auth.go:149). This path generates an AuthID and registers the node after the user completes the web/OIDC flow. Errors include the registration-ID generation failure (see 'generating registration ID') and any state/DB errors while creating or updating the pending registration and node record.
Source
Thrown at hscontrol/auth.go:149
// logins as they can be done fully sync and we can respond to the node with
// the result as it is waiting.
if isAuthKey(req) {
resp, err := h.handleRegisterWithAuthKey(req, machineKey)
if err != nil {
// Preserve HTTPError types so they can be handled properly by the HTTP layer
if httpErr, ok := errors.AsType[HTTPError](err); ok {
return nil, httpErr
}
return nil, fmt.Errorf("handling register with auth key: %w", err)
}
return resp, nil
}
resp, err := h.handleRegisterInteractive(req, machineKey)
if err != nil {
return nil, fmt.Errorf("handling register interactive: %w", err)
}
return resp, nil
}
// handleLogout checks if the [tailcfg.RegisterRequest] is a
// logout attempt from a node. If the node is not attempting to.
func (h *Headscale) handleLogout(
node types.NodeView,
req tailcfg.RegisterRequest,
machineKey key.MachinePublic,
) (*tailcfg.RegisterResponse, error) {
// Fail closed if it looks like this is an attempt to modify a node where
// the node key and the machine key the noise session was started with does
// not align.
err := machineKeyMismatch(node, machineKey)
if err != nil {
return nil, errView on GitHub (pinned to 565fd254d0)
Solutions
- Inspect the wrapped error in the headscale log — it names the actual failing step (ID generation vs DB write).
- Restore database health (connectivity, locks, disk space) and retry the login from the node; interactive registration can simply be re-attempted.
- As a workaround for automation, switch to pre-auth keys which bypass the interactive flow.
- If caused by parallel interactive logins on SQLite, serialize enrollments or use PostgreSQL.
Defensive patterns
Strategy: retry
Try / catch
resp, err := h.handleRegister(req, mk)
if err != nil && strings.Contains(err.Error(), "handling register interactive") {
// re-attempt `tailscale login` once DB/entropy issue clears; or switch to preauth key flow
} Prevention
- Use pre-auth keys for automation to avoid the interactive path entirely.
- Keep DB connectivity healthy during interactive enrollments.
- Alert on registration-endpoint 5xx rates.
When it happens
Trigger: `tailscale login` / `tailscale up` without an auth key: the node contacts the register endpoint, and creation of the interactive-registration record or subsequent node persistence fails on a database error; entropy source failure when generating the AuthID.
Common situations: Interactive enrollment during DB outages; SQLite lock contention when a browser callback races other writes; heavily loaded control servers with exhausted connection pools.
Related errors
- handling logout: %w
- handling existing node: %w
- handling register with auth key: %w
- deleting ephemeral node: %w
- setting node expiry: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/c52253e361170aba.
Report an issue: GitHub.