juanfont/headscale · warning

--name or --identifier flag is required

Error message

--name or --identifier flag is required

What it means

HTTP 405 from PingResponseHandler, the in-noise endpoint clients call (HEAD) to prove connectivity after receiving a tailcfg.PingRequest. The authentication is the unguessable ping ID, so any non-HEAD verb is rejected outright before the ID is even inspected.

Source

Thrown at cmd/headscale/cli/users.go:20

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strconv"

	clientv1 "github.com/juanfont/headscale/gen/client/v1"
	"github.com/juanfont/headscale/hscontrol/util"
	"github.com/juanfont/headscale/hscontrol/util/zlog/zf"
	"github.com/rs/zerolog/log"
	"github.com/spf13/cobra"
)

// CLI user errors.
var (
	errFlagRequired       = errors.New("--name or --identifier flag is required")
	errMultipleUsersMatch = errors.New("multiple users match query, specify an ID")
)

func usernameAndIDFlag(cmd *cobra.Command) {
	cmd.Flags().Int64P("identifier", "i", -1, "User identifier (ID)")
	cmd.Flags().StringP("name", "n", "", "Username")
}

// usernameAndIDFromFlag returns the username and ID from the flags of the command.
func usernameAndIDFromFlag(cmd *cobra.Command) (uint64, string, error) {
	username, _ := cmd.Flags().GetString("name")

	identifier, _ := cmd.Flags().GetInt64("identifier")
	if username == "" && identifier < 0 {
		return 0, "", errFlagRequired
	}

	// Normalise unset/negative identifiers to 0 so the uint64

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use HEAD: curl -I 'https://host/ts2021/ping-response?id=<id>' (inside the noise tunnel, clients do this automatically).
  2. In client code, answer tailcfg.PingRequest with an http.HEAD request carrying the ?id= query parameter.
  3. Do not probe this path with GET/POST — there is no GET fallback by design.

Example fix

# before (405 method not allowed)
curl 'http://host/.../ping-response?id=abc'

# after
curl -I 'http://host/.../ping-response?id=abc'
Defensive patterns

Strategy: validation

Validate before calling

// Always issue HEAD for ping responses.
if method != http.MethodHead {
    return fmt.Errorf("ping-response endpoint requires HEAD, got %s", method)
}
req, _ := http.NewRequest(http.MethodHead, pingURL, nil)

Prevention

When it happens

Trigger: Sending GET or POST to the ping-response path inside the noise tunnel; curl without -I/--head; a custom client implementing the ping responder with the wrong method.

Common situations: Manually testing the endpoint with curl (default GET) while debugging derp/connectivity; client code that answers PingRequest with GET.

Related errors


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