{"record":{"id":"9d63f387e59e2ed2","repo":"juanfont/headscale","slug":"logging-in-new-client-w","errorCode":null,"errorMessage":"logging in new client: %w","messagePattern":"logging in new client: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integration/helpers.go","lineNumber":1201,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"timeout waiting for new client: %w\", err)\n\t}\n\n\t// Get the user and create preauth key\n\tuser, err := GetUserByName(headscale, username)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting user: %w\", err)\n\t}\n\n\tauthKey, err := s.CreatePreAuthKey(mustParseID(user.Id), true, false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating preauth key: %w\", err)\n\t}\n\n\t// Login the new client\n\terr = newClient.Login(headscale.GetEndpoint(), authKey.Key)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"logging in new client: %w\", err)\n\t}\n\n\treturn newClient, nil\n}\n\n// MustAddAndLoginClient is like [Scenario.AddAndLoginClient] but fails the test on error.\nfunc (s *Scenario) MustAddAndLoginClient(\n\tt *testing.T,\n\tusername string,\n\tversion string,\n\theadscale ControlServer,\n\ttsOpts ...tsic.Option,\n) TailscaleClient {\n\tt.Helper()\n\n\tclient, err := s.AddAndLoginClient(t, username, version, headscale, tsOpts...)\n\trequire.NoError(t, err)\n","sourceCodeStart":1183,"sourceCodeEnd":1219,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/integration/helpers.go#L1183-L1219","documentation":"Final step error in Scenario.AddAndLoginClient: newClient.Login(headscale.GetEndpoint(), authKey.Key) failed. Login runs `tailscale up --login-server <endpoint> --authkey <key>` (plus options) inside the new tailscale container; failure means the node could not authenticate against headscale with the preauth key.","triggerScenarios":"Invalid/expired/reused preauth key; wrong endpoint (TLS hostname mismatch); tailscale client cannot reach the headscale port; authkey rejected because the node was already registered with different identity; version incompatibility between client and server noise protocol.","commonSituations":"Non-reusable key consumed by an earlier attempt; TLS cert hostname not matching the endpoint used; headscale server_url misconfigured in MinimumConfigYAML; old tailscale image lacking current noise handshake support.","solutions":["Read the tailscale container log for the `tailscale up` error (authkey rejected vs dial error vs TLS error)","Confirm headscale.GetEndpoint() matches the server_url/TLS hostname configured for the container","Verify the preauth key was created reusable and used only once per fresh node","Check hs-*.stderr.log for registration endpoint errors"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Sanity-check endpoint and key before login\nif authKey.Key == \"\" { t.Fatal(\"empty authkey\") }\nep := headscale.GetEndpoint()\nif ep == \"\" { t.Fatal(\"empty headscale endpoint\") }","typeGuard":null,"tryCatchPattern":"if err := newClient.Login(headscale.GetEndpoint(), authKey.Key); err != nil {\n    // dump tailscale container log for the real `tailscale up` failure\n    newClient.MustLog(t) // or read container logs\n    t.Fatalf(\"login failed: %v\", err)\n}","preventionTips":["Use reusable=false keys only once per fresh container; prefer fresh keys per node","Ensure TLS hostname matches the endpoint passed to Login","Always capture the tailscale container log on login failure"],"tags":["integration-test","login","authkey","tailscale-client"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}