juanfont/headscale · error
saving node to database: %w
Error message
saving node to database: %w
What it means
The save for a node taking the fresh-registration path (it had no existing IPs): after assigning ipv4/ipv6 and defaulting GivenName, tx.Save persists the new node row. Failure means the INSERT/UPDATE was rejected — unique constraint on machine key, node key, or given name, or a database availability error.
Source
Thrown at hscontrol/db/node.go:335
Str(zf.NodeKey, node.NodeKey.ShortString()).
Str(zf.UserName, node.User.Username()).
Msg("Test node authorized again")
return &node, nil
}
node.IPv4 = ipv4
node.IPv6 = ipv6
if node.GivenName == "" {
node.GivenName = dnsname.SanitizeHostname(node.Hostname)
if node.GivenName == "" {
node.GivenName = "node"
}
}
if err := tx.Save(&node).Error; err != nil { //nolint:noinlineerr
return nil, fmt.Errorf("saving node to database: %w", err)
}
log.Trace().
Caller().
Str(zf.NodeHostname, node.Hostname).
Msg("Test node registered with the database")
return &node, nil
}
// NodeSetNodeKey sets the node key of a node and saves it to the database.
func NodeSetNodeKey(tx *gorm.DB, node *types.Node, nodeKey key.NodePublic) error {
return tx.Model(node).Updates(types.Node{
NodeKey: nodeKey,
}).Error
}
func (hsdb *HSDatabase) NodeSetMachineKey(View on GitHub (pinned to 565fd254d0)
Solutions
- Unwrap the driver error to identify the violated constraint
- Ensure the user record exists and is committed before registering the node
- For duplicate-machine-key races, retry registration so the existing-node path handles it
- Fix underlying DB health if the error is lock/connectivity
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the owning user row is committed before registering
if _, err := db.GetUserByID(uid); err != nil {
return nil, fmt.Errorf("cannot register node for missing user: %w", err)
} Try / catch
if _, err := db.RegisterNode(tx, node); err != nil {
if isUniqueViolation(err) || isTransientDBError(err) {
// retryable: race or lock
}
return err
} Prevention
- Commit user creation before node registration
- Prefer servertest harness to reproduce registration races
- Alert on registration-path 5xx to catch schema drift early
When it happens
Trigger: Same machine registering twice concurrently; expired node re-registering with a key that now duplicates another row; DB lock/timeout; NOT NULL or foreign-key violation (e.g. user id not yet committed).
Common situations: Race between interactive auth callback and client poll; automation pre-creating rows; partial migration leaving constraints inconsistent.
Related errors
- registering existing node in database: %w
- saving oauth client: %w
- saving node(%d) after adding IPs: %w
- checking name uniqueness: %w
- renaming node in database: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/affa37e3f1e266cb.
Report an issue: GitHub.