juanfont/headscale · error
auto approving routes: %w
Error message
auto approving routes: %w
What it means
Wraps a failure of h.state.AutoApproveRoutes(node) at the end of registration with an auth key (hscontrol/auth.go:453). After the node is persisted and added to the policy manager, routes the node advertises and the policy allows are auto-approved; this error means that approval step (route matching plus a subsequent state save of the node) failed. Note the comment in the source: the node add and the route approval are two separate saves, so a failure here can leave the node registered but its routes unapproved.
Source
Thrown at hscontrol/auth.go:453
return nil, nil //nolint:nilnil // intentional: no node to return when ephemeral deleted
}
// This is a bit of a back and forth, but we have a bit of a chicken and egg
// dependency here.
// Because the way the policy manager works, we need to have the node
// in the database, then add it to the policy manager and then we can
// approve the route. This means we get this dance where the node is
// first added to the database, then we add it to the policy manager via
// nodesChangedHook and then we can auto approve the routes.
// As that only approves the struct object, we need to save it again and
// ensure we send an update.
// This works, but might be another good candidate for doing some sort of
// eventbus.
// TODO(kradalby): This needs to be ran as part of the batcher maybe?
// now since we dont update the node/pol here anymore
routesChange, err := h.state.AutoApproveRoutes(node)
if err != nil {
return nil, fmt.Errorf("auto approving routes: %w", err)
}
// Send both changes. Empty changes are ignored by Change().
h.Change(changed, routesChange)
resp := &tailcfg.RegisterResponse{
MachineAuthorized: true,
NodeKeyExpired: node.IsExpired(),
User: node.Owner().TailscaleUser(),
Login: node.Owner().TailscaleLogin(),
}
log.Trace().
Caller().
Interface("reg.resp", resp).
Interface("reg.req", req).
EmbedObject(node).
Msg("RegisterResponse")View on GitHub (pinned to 565fd254d0)
Solutions
- Check whether the node itself registered (it likely did) and only route approval failed: `headscale nodes list` and `headscale routes list`.
- Approve the routes manually: `headscale routes enable -r <route-id>` (or the corresponding route approve command).
- Fix the underlying DB issue reported in the wrapped error (locks/connectivity) so future registrations auto-approve.
- Retry registration if the node state is inconsistent; re-running with the same auth key policy re-attempts approval.
Defensive patterns
Strategy: fallback
Try / catch
resp, err := h.handleRegister(req, mk)
if err != nil && strings.Contains(err.Error(), "auto approving routes") {
// node registration itself likely succeeded: check `headscale routes list` and approve manually
} Prevention
- After registering subnet routers, verify routes: `headscale routes list` and enable missed ones.
- Keep autoApprovers policy stable during enrollment windows.
- Remember the two-phase save: registration and route approval are separate writes; monitor both.
When it happens
Trigger: Registering a node that advertises subnet routes (--advertise-routes) with an autoApprovers policy entry, while the second state save fails: DB lock, connection drop, or policy manager inconsistency after the node was added.
Common situations: Subnet routers registering under load on SQLite; policy file changed concurrently with registration; DB transient failures during bulk router enrollment.
Related errors
- invalid auto approver format
- requested tags
- loading policy from database: %w
- loading users for policy validation: %w
- setting ACL policy: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/163bb0dbeb7b84a4.
Report an issue: GitHub.