juanfont/headscale · error · HTTPError

Internal error

Error message

Internal error

What it means

Returned by sshActionHoldAndDelegate when url.Parse fails on the internally constructed hold URL (ServerURL + /machine/ssh/action/... with $ placeholders). Because the path is a fixed constant, failure can only come from a malformed ServerURL configuration that makes the combined URL unparseable.

Source

Thrown at hscontrol/noise.go:531

// sshActionHoldAndDelegate creates a new auth session bound to the
// (src, dst) pair and returns a [tailcfg.SSHAction.HoldAndDelegate] action that directs the
// client to authenticate.
func (ns *noiseServer) sshActionHoldAndDelegate(
	reqLog zerolog.Logger,
	action *tailcfg.SSHAction,
	srcNodeID, dstNodeID types.NodeID,
) (*tailcfg.SSHAction, error) {
	holdURL, err := url.Parse(
		ns.headscale.cfg.ServerURL +
			"/machine/ssh/action/$SRC_NODE_ID/to/$DST_NODE_ID" +
			"?local_user=$LOCAL_USER",
	)
	if err != nil {
		return nil, NewHTTPError(
			http.StatusInternalServerError,
			"Internal error",
			fmt.Errorf("parsing SSH action URL: %w", err),
		)
	}

	authID, err := types.NewAuthID()
	if err != nil {
		return nil, NewHTTPError(
			http.StatusInternalServerError,
			"Internal error",
			fmt.Errorf("generating auth ID: %w", err),
		)
	}

	ns.headscale.state.SetAuthCacheEntry(
		authID,
		types.NewSSHCheckAuthRequest(srcNodeID, dstNodeID),
	)

	authURL := ns.headscale.authProvider.AuthURL(authID)

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Print and inspect the configured server_url for stray characters
  2. Set server_url to a clean absolute URL like https://headscale.example.com
  3. Restart headscale after fixing the config

Example fix

# before
server_url: https://headscale.example.com\x0b

# after
server_url: https://headscale.example.com
Defensive patterns

Strategy: validation

Validate before calling

if u, err := url.Parse(cfg.ServerURL); err != nil || !u.IsAbs() {
    return errors.New("server_url must be a valid absolute URL")
}

Prevention

When it happens

Trigger: cfg.ServerURL containing characters that break URL parsing when concatenated (control characters, invalid percent-encoding).

Common situations: HEADCSCALE_SERVER_URL pasted with hidden control characters or an invalid scheme; a config typo introduced during deployment.

Related errors


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