{"record":{"id":"d982df51a76e76c7","repo":"hashicorp/nomad","slug":"failed-joining-s","errorCode":null,"errorMessage":"failed joining: %s","messagePattern":"failed joining: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/agent.go","lineNumber":140,"sourceCode":"}\n\n// Join is used to instruct a server node to join another server\n// via the gossip protocol. Multiple addresses may be specified.\n// We attempt to join all the hosts in the list. Returns the\n// number of nodes successfully joined and any error. If one or\n// more nodes have a successful result, no error is returned.\nfunc (a *Agent) Join(addrs ...string) (int, error) {\n\t// Accumulate the addresses\n\tv := url.Values{}\n\tfor _, addr := range addrs {\n\t\tv.Add(\"address\", addr)\n\t}\n\n\t// Send the join request\n\tvar resp joinResponse\n\t_, err := a.client.put(\"/v1/agent/join?\"+v.Encode(), nil, &resp, nil)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed joining: %s\", err)\n\t}\n\tif resp.Error != \"\" {\n\t\treturn 0, fmt.Errorf(\"failed joining: %s\", resp.Error)\n\t}\n\tif resp.Warning != \"\" {\n\t\treturn resp.NumJoined, errors.New(resp.Warning)\n\t}\n\treturn resp.NumJoined, nil\n}\n\n// Members is used to query all of the known server members\nfunc (a *Agent) Members() (*ServerMembers, error) {\n\tvar resp *ServerMembers\n\n\t// Query the known members\n\t_, err := a.client.query(\"/v1/agent/members\", &resp, nil)\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/agent.go#L122-L158","documentation":"Agent.Join() in api/agent.go issues a PUT to /v1/agent/join; if the HTTP request itself fails, the error is wrapped as \"failed joining: %s\" (this index is the client-error branch). It signals the join RPC never completed successfully at the transport/API level.","triggerScenarios":"Calling Agent.Join(addresses, wan) when the PUT fails — agent unreachable, 403 from ACLs, or the target address parameter is invalid enough that the agent rejects the request.","commonSituations":"Joining a cluster from automation where the local agent is down or the ACL token lacks `agent:write`; wrong WAN flag; DNS resolution failure for the join address.","solutions":["Inspect the wrapped error: fix connectivity (agent down/wrong port) or supply an ACL token with agent write permissions.","Verify the join address is a reachable Consul agent and includes the correct port (8301 by default).","Retry with correct `wan` boolean (false for LAN pool) and check agent logs for the join rejection reason."],"exampleFix":"// before\n_, err := agent.Join([]string{\"10.0.0.5\"}, true) // 403: no token\n// after\nclient.SetToken(os.Getenv(\"CONSUL_HTTP_TOKEN\"))\n_, err := agent.Join([]string{\"10.0.0.5:8301\"}, false)","handlingStrategy":"try-catch","validationCode":"// ensure local agent API is up and token present before Join\nif err := checkAgentHealth(client); err != nil {\n    return fmt.Errorf(\"cannot join: local agent unavailable: %w\", err)\n}\nif client.Token() == \"\" && aclsEnabled {\n    return fmt.Errorf(\"join requires an ACL token with agent:write\")\n}","typeGuard":null,"tryCatchPattern":"n, err := agent.Join(addrs, wan)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed joining\") {\n        return fmt.Errorf(\"join request failed, check ACL token/agent address: %w\", err)\n    }\n    return err\n}","preventionTips":["Ensure the ACL token used has `agent:write` on the local node.","Use fully qualified join addresses with explicit ports.","Confirm the local agent's HTTP API health before cluster operations."],"tags":["http","api","cluster-join","consul-agent"],"backgroundTag":"http-request-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}