{"record":{"id":"e8047057f7906782","repo":"juanfont/headscale","slug":"listing-updated-clients-w","errorCode":null,"errorMessage":"listing updated clients: %w","messagePattern":"listing updated clients: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integration/helpers.go","lineNumber":1169,"sourceCode":"\t// Get the original client list\n\toriginalClients, err := s.ListTailscaleClients(username)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"listing original clients: %w\", err)\n\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","sourceCodeStart":1151,"sourceCodeEnd":1187,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/integration/helpers.go#L1151-L1187","documentation":"Thrown inside a backoff.Retry loop in Scenario.AddAndLoginClient when s.ListTailscaleClients(username) returns an error while polling for a newly created tailscale node to appear. The list call executes `headscalectl listnodes` (or equivalent) inside the headscale container, so any container exec failure, CLI error, or malformed output surfaces here. The retry wrapper keeps invoking it for up to 10s, so this error only propagates if listing fails every attempt.","triggerScenarios":"Calling Scenario.AddAndLoginClient after CreateTailscaleNodesInUser; each 500ms retry invokes Scenario.ListTailscaleClients(username), which shells into the headscale container and parses node-list JSON. Fails when the headscale container is not running, the exec times out, the CLI exits non-zero, or node JSON cannot be decoded.","commonSituations":"Head scale container crashed mid-test; Docker daemon under load causing exec timeouts; headscale not yet listening when the first list attempts run; a broken/unbuilt headscale binary inside the container returning errors on every invocation.","solutions":["Check hs-*.stderr.log in control_logs/<runID>/ to see why the headscale CLI failed inside the container","Verify the headscale container is still running (docker ps) and did not OOM or panic during the test","Re-run with `go run ./cmd/hi doctor` to validate the Docker environment before the test","If the container starts slowly, ensure earlier wait-for-healthy logic completed before AddAndLoginClient is called"],"exampleFix":"// No code fix; the wrapping backoff.Retry already retries for 10s.\n// If listing fails the whole time, inspect container logs:\n//   docker logs <headscale-container> --tail 100","handlingStrategy":"retry","validationCode":"// Pre-condition: headscale container healthy before adding clients\nif err := headscale.WaitForRunning(30 * time.Second); err != nil {\n    t.Fatalf(\"headscale not ready: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"// The backoff.Retry already retries; treat final error as fatal for the test:\nclient, err := scenario.AddAndLoginClient(t, user, ver)\nif err != nil {\n    t.Fatalf(\"AddAndLoginClient failed (check hs-*.stderr.log): %v\", err)\n}","preventionTips":["Always wait for the headscale container to be healthy before creating nodes","Keep control_logs run IDs and read hs-*.stderr.log on any listing failure","Run `go run ./cmd/hi doctor` before integration suites"],"tags":["integration-test","docker","retry","headscale-cli"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}