{"record":{"id":"ca12c33572384dcf","repo":"hashicorp/nomad","slug":"start-join-is-not-supported-for-nomad-clients","errorCode":null,"errorMessage":"start_join is not supported for Nomad clients","messagePattern":"start_join is not supported for Nomad clients","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"command/agent/retry_join.go","lineNumber":151,"sourceCode":"\t\t}\n\t\tif config.Server.RetryMaxAttempts != 0 {\n\t\t\treturn fmt.Errorf(\"server_join and retry_max cannot both be defined; prefer setting the server_join block\")\n\t\t}\n\n\t\tif config.Server.RetryInterval != 0 {\n\t\t\treturn fmt.Errorf(\"server_join and retry_interval cannot both be defined; prefer setting the server_join block\")\n\t\t}\n\n\t\tif len(config.Server.ServerJoin.StartJoin) != 0 {\n\t\t\treturn fmt.Errorf(\"retry_join and start_join cannot both be defined\")\n\t\t}\n\t}\n\n\t// if retry_join is defined for the client, ensure that start_join is not\n\t// set as this configuration is only defined for servers.\n\tif config.Client != nil && config.Client.ServerJoin != nil {\n\t\tif config.Client.ServerJoin.StartJoin != nil {\n\t\t\treturn fmt.Errorf(\"start_join is not supported for Nomad clients\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// RetryJoin is used to handle retrying a join until it succeeds or all retries\n// are exhausted.\nfunc (r *retryJoiner) RetryJoin() {\n\tif len(r.joinCfg.RetryJoin) == 0 {\n\t\treturn\n\t}\n\n\tattempt := 0\n\n\taddrsToJoin := strings.Join(r.joinCfg.RetryJoin, \" \")\n\tr.logger.Info(\"starting retry join\", \"servers\", addrsToJoin)\n","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/agent/retry_join.go#L133-L169","documentation":"start_join (and its server_join.start_join form) only makes sense for Nomad servers performing Raft bootstrap/manual joins. If a client stanza defines ServerJoin.StartJoin, Validate rejects the config because clients never start-join a cluster.","triggerScenarios":"Config with client { server_join { start_join = [...] } } set to a non-nil value; retryJoiner.Validate fails at agent startup.","commonSituations":"Using one shared config file for both servers and clients and including server-only keys; copy-pasting a server config block into the client stanza.","solutions":["Remove client.server_join.start_join from the client config","Move start_join to the server stanza's server_join block where it is valid","For clients, only use client.server_join.retry_join / retry_max / retry_interval","Split shared and role-specific config files so server keys never leak into client configs"],"exampleFix":"// before\nclient {\n  server_join {\n    start_join = [\"10.0.0.1\"]\n  }\n}\n// after\nclient {\n  server_join {\n    retry_join = [\"10.0.0.1\"]\n  }\n}","handlingStrategy":"validation","validationCode":"if c := cfg.Client; c != nil && c.ServerJoin != nil && c.ServerJoin.StartJoin != nil {\n    return errors.New(\"start_join is invalid in the client stanza\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never place server-only keys in the client stanza","Use separate config files for server and client roles","Template shared configs with role guards for server-only fields","Run nomad config validate with the actual role flags (-client/-server)"],"tags":["nomad","configuration","validation","client"],"backgroundTag":"invalid-config-key","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"}