juanfont/headscale · error

parsing IP address from database: %w

Error message

parsing IP address from database: %w

What it means

Each stored node address string from the ipv4/ipv6 columns is parsed with netip.ParseAddr; failure means a stored value is not a valid IP literal. This is a data-corruption error: headscale itself only ever writes parseable addresses, so a bad value implies external modification or a damaged database.

Source

Thrown at hscontrol/db/ip.go:119

		// the database into account to start at a more "educated" location.
		ret.prev4 = network4
	}

	if prefix6 != nil {
		network6, broadcast6 := util.GetIPPrefixEndpoints(*prefix6)
		ips.Add(network6)
		ips.Add(broadcast6)

		ret.prev6 = network6
	}

	// Fetch all the IP Addresses currently handed out from the Database
	// and add them to the used IP set.
	for _, addrStr := range append(v4s, v6s...) {
		if addrStr.Valid {
			addr, err := netip.ParseAddr(addrStr.String)
			if err != nil {
				return nil, fmt.Errorf("parsing IP address from database: %w", err)
			}

			ips.Add(addr)
		}
	}

	// Build the initial IPSet to validate that we can use it.
	_, err := ips.IPSet()
	if err != nil {
		return nil, fmt.Errorf(
			"building initial IP Set: %w",
			err,
		)
	}

	ret.usedIPs = ips

	return &ret, nil

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Find the offending rows: SELECT id, hostname, ipv4, ipv6 FROM nodes WHERE ipv4 IS NOT NULL AND ipv4 != '' (inspect values manually).
  2. Correct or NULL out the malformed address and restart headscale.
  3. Never edit node IPs by hand — delete/re-register the node or use the API instead.

Example fix

-- before (corrupt row)
UPDATE nodes SET ipv4 = '10.0.0.300' WHERE id = 7; -- invalid literal

-- after
UPDATE nodes SET ipv4 = '10.0.0.7' WHERE id = 7;
-- or remove and re-register the node
Defensive patterns

Strategy: validation

Validate before calling

// Audit stored addresses before allocator construction:
// SELECT id, ipv4, ipv6 FROM nodes
//   WHERE (ipv4 IS NOT NULL AND ipv4 != '' AND ipv4 NOT GLOB '*.*.*')
//      OR (ipv6 IS NOT NULL AND ipv6 = '');
-- Or in Go over the plucked values:
func allParseable(vals []sql.NullString) bool {
    for _, v := range vals {
        if v.Valid && v.String != "" {
            if _, err := netip.ParseAddr(v.String); err != nil { return false }
        }
    }
    return true
}

Try / catch

// Not retryable — repair data. Locate the malformed row via the audit
// query, fix or NULL it, then restart. Escalate if rows were written by
// headscale itself (that would be a bug worth reporting upstream).

Prevention

When it happens

Trigger: Someone hand-edited nodes.ipv4/ipv6 (e.g. set it to '10.0.0.256', an empty-but-non-null string, or a hostname); a buggy older version or external script wrote malformed values.

Common situations: Manual 'fixes' via SQL UPDATE on the nodes table; imports from third-party tooling; encoding corruption in a restored backup.

Related errors


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