tailscale/tailscale · error
invalid device name %q
Error message
invalid device name %q
What it means
NewDeeplink field check: DeviceName must be non-empty; it becomes the 'dn' query parameter of the sign deeplink so the approver can see which device they are signing. A zero-value struct field triggers this rejection before signing.
Source
Thrown at tka/deeplink.go:57
type NewDeeplinkParams struct {
NodeKey string
TLPub string
DeviceName string
OSName string
LoginName string
}
// NewDeeplink creates a signed deeplink using the authority's stateID as a
// secret. This deeplink can then be validated by ValidateDeeplink.
func (a *Authority) NewDeeplink(params NewDeeplinkParams) (string, error) {
if params.NodeKey == "" || !strings.HasPrefix(params.NodeKey, "nodekey:") {
return "", fmt.Errorf("invalid node key %q", params.NodeKey)
}
if params.TLPub == "" || !strings.HasPrefix(params.TLPub, "tlpub:") {
return "", fmt.Errorf("invalid tlpub %q", params.TLPub)
}
if params.DeviceName == "" {
return "", fmt.Errorf("invalid device name %q", params.DeviceName)
}
if params.OSName == "" {
return "", fmt.Errorf("invalid os name %q", params.OSName)
}
if params.LoginName == "" {
return "", fmt.Errorf("invalid login name %q", params.LoginName)
}
u := url.URL{
Scheme: DeeplinkTailscaleURLScheme,
Host: DeeplinkCommandSign,
Path: "/v1/",
}
v := url.Values{}
v.Set("nk", params.NodeKey)
v.Set("tp", params.TLPub)
v.Set("dn", params.DeviceName)
v.Set("os", params.OSName)View on GitHub (pinned to 6e0912f979)
Solutions
- Populate DeviceName from the node's hostname/profile data before calling
- Default it to a generated name if the hostname is empty
- Validate all five params in one helper before calling NewDeeplink
Example fix
// before
p := tka.NewDeeplinkParams{NodeKey: nk, TLPub: tp, OSName: runtime.GOOS}
// after
p := tka.NewDeeplinkParams{NodeKey: nk, TLPub: tp, DeviceName: host.Name(), OSName: runtime.GOOS} Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(p.DeviceName) == "" {
return errors.New("device name required before minting a sign deeplink")
} Type guard
func nonEmpty(s string) bool { return strings.TrimSpace(s) != "" } Prevention
- Populate all five NewDeeplinkParams fields from one profile/hostname source
- Run a single validateParams helper before calling NewDeeplink
- Treat empty strings as bugs in the producer, not defaults
When it happens
Trigger: NewDeeplinkParams built with DeviceName left "" - a forgotten profile field, an empty hostname, or a struct literal missing the field.
Common situations: Zero-value params structs; provisioning flows where the device hostname is not yet set when the deeplink is minted.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- invalid os name %q
- invalid login name %q
- sending verify-deeplink: %w
- invalid node key %q
- invalid tlpub %q
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/26911992439cd87b.
Report an issue: GitHub.