{"record":{"id":"8b8a251f897adf8e","repo":"juanfont/headscale","slug":"expected-d-clients-got-d","errorCode":null,"errorMessage":"expected %d clients, got %d","messagePattern":"expected (.+?) clients, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integration/helpers.go","lineNumber":1173,"sourceCode":"\t}\n\n\t// Create the new node\n\terr = s.CreateTailscaleNodesInUser(username, version, 1, tsOpts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating tailscale node: %w\", err)\n\t}\n\n\t// Wait for the new node to appear in the client list\n\tvar newClient TailscaleClient\n\n\t_, err = backoff.Retry(t.Context(), func() (struct{}, error) {\n\t\tupdatedClients, err := s.ListTailscaleClients(username)\n\t\tif err != nil {\n\t\t\treturn struct{}{}, fmt.Errorf(\"listing updated clients: %w\", err)\n\t\t}\n\n\t\tif len(updatedClients) != len(originalClients)+1 {\n\t\t\treturn struct{}{}, fmt.Errorf(\"expected %d clients, got %d\", len(originalClients)+1, len(updatedClients)) //nolint:err113\n\t\t}\n\n\t\tnewClient, err = FindNewClient(originalClients, updatedClients)\n\t\tif err != nil {\n\t\t\treturn struct{}{}, fmt.Errorf(\"finding new client: %w\", err)\n\t\t}\n\n\t\treturn struct{}{}, nil\n\t}, backoff.WithBackOff(backoff.NewConstantBackOff(500*time.Millisecond)), backoff.WithMaxElapsedTime(10*time.Second))\n\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}","sourceCodeStart":1155,"sourceCodeEnd":1191,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/integration/helpers.go#L1155-L1191","documentation":"Emitted from the retry lambda in Scenario.AddAndLoginClient when the number of clients returned by ListTailscaleClients does not equal the pre-creation count plus one. It is an assertion-style error (nolint:err113) used as a retry signal: the newly created container node has not registered with headscale yet, so the count check fails and backoff.Retry re-invokes the lambda after 500ms.","triggerScenarios":"Scenario.CreateTailscaleNodesInUser started a new tailscale container, but the node has not completed registration with the control server yet (or never will because its container is broken). Every retry sees len(updatedClients) != len(originalClients)+1 for 10 seconds, then the error propagates wrapped as 'timeout waiting for new client'.","commonSituations":"Slow or overloaded Docker host so tailscaled takes >10s to register; wrong tailscale version image that cannot talk to the headscale API; TLS mismatch so the node registration silently fails; headscale server rejecting registrations due to policy config.","solutions":["Read the new tailscale container's logs (docker logs) to see if tailscaled failed to register or retried in a loop","Check hs-*.stderr.log for registration errors such as TLS or noise handshake failures","Free Docker resources or raise backoff.WithMaxElapsedTime if the host is consistently slow","Verify the tailscale image version is compatible with the headscale version under test"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat this error as a timing signal, not a bug: it only surfaces after 10s of registration not completing","Keep Docker host load low; avoid running many suites in parallel on one daemon","Pin tailscale image versions known to work with the headscale version under test"],"tags":["integration-test","node-registration","retry","timing"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}