hashicorp/nomad · error
server_join and retry_max cannot both be defined; prefer set
Error message
server_join and retry_max cannot both be defined; prefer setting the server_join block
What it means
retryJoiner.Validate rejects configurations where the server_join block and the deprecated top-level retry_max field are both set. retry_max (max join attempts) now lives inside server_join as retry_max_attempts.
Source
Thrown at command/agent/retry_join.go:135
// logger is the retry joiners logger
logger log.Logger
}
// Validate ensures that the configuration passes validity checks for the
// retry_join block. If the configuration is not valid, returns an error that
// will be displayed to the operator, otherwise nil.
func (r *retryJoiner) Validate(config *Config) error {
// If retry_join is defined for the server, ensure that deprecated
// fields and the server_join block are not both set
if config.Server != nil && config.Server.ServerJoin != nil && len(config.Server.ServerJoin.RetryJoin) != 0 {
if len(config.Server.RetryJoin) != 0 {
return fmt.Errorf("server_join and retry_join cannot both be defined; prefer setting the server_join block")
}
if len(config.Server.StartJoin) != 0 {
return fmt.Errorf("server_join and start_join cannot both be defined; prefer setting the server_join block")
}
if config.Server.RetryMaxAttempts != 0 {
return fmt.Errorf("server_join and retry_max cannot both be defined; prefer setting the server_join block")
}
if config.Server.RetryInterval != 0 {
return fmt.Errorf("server_join and retry_interval cannot both be defined; prefer setting the server_join block")
}
if len(config.Server.ServerJoin.StartJoin) != 0 {
return fmt.Errorf("retry_join and start_join cannot both be defined")
}
}
// if retry_join is defined for the client, ensure that start_join is not
// set as this configuration is only defined for servers.
if config.Client != nil && config.Client.ServerJoin != nil {
if config.Client.ServerJoin.StartJoin != nil {
return fmt.Errorf("start_join is not supported for Nomad clients")
}
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Remove top-level server.retry_max and set server_join { retry_max_attempts } instead
- Audit the server stanza for other deprecated keys (retry_join, start_join, retry_interval) and migrate them together
- Validate the config with nomad config validate before restart
Example fix
// before
server {
retry_max = 5
server_join {
retry_join = ["1.2.3.4"]
}
}
// after
server {
server_join {
retry_join = ["1.2.3.4"]
retry_max_attempts = 5
}
} Defensive patterns
Strategy: validation
Validate before calling
if s := cfg.Server; s != nil && s.ServerJoin != nil && len(s.ServerJoin.RetryJoin) > 0 && s.RetryMaxAttempts != 0 {
return errors.New("move retry_max into server_join.retry_max_attempts")
} Prevention
- Set retry_max_attempts inside server_join, not top-level retry_max
- Run nomad config validate in CI
- Audit pre-upgrade configs for deprecated server keys
- Keep a single canonical server_join config template
When it happens
Trigger: Config where server.server_join.retry_join is set AND server.retry_max != 0; Validate fails during agent startup config parsing.
Common situations: Old configs carrying retry_max from pre-server_join versions, then adding server_join; copy-paste between old and new config examples.
Related errors
- server_join and retry_join cannot both be defined; prefer se
- server_join and start_join cannot both be defined; prefer se
- server_join and retry_interval cannot both be defined; prefe
- Reschedule policy has unlimited attempts enabled and a low d
- Lock delay and TTL must be positive
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/94cbe1ea1bed7230.
Report an issue: GitHub.