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, err

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Inspect the wrapped error in the headscale log — it names the actual failing step (ID generation vs DB write).
  2. Restore database health (connectivity, locks, disk space) and retry the login from the node; interactive registration can simply be re-attempted.
  3. As a workaround for automation, switch to pre-auth keys which bypass the interactive flow.
  4. 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

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


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