hashicorp/nomad · error

rpc_handshake_timeout must be >= 0

Error message

rpc_handshake_timeout must be >= 0

What it means

After parsing limits.rpc_handshake_timeout, convertServerConfig rejects negative durations: a negative handshake timeout is meaningless (a TCP/TLS handshake can't complete in negative time), so the agent refuses to start or reload rather than silently misconfiguring the RPC layer.

Source

Thrown at command/agent/agent.go:598

		}
		if agentConfig.RPC.DialTimeout > 0 {
			conf.RPCDialTimeout = agentConfig.RPC.DialTimeout
		}
	}

	// Set the TLS config
	conf.TLSConfig = agentConfig.TLSConfig

	// Setup telemetry related config
	conf.StatsCollectionInterval = agentConfig.Telemetry.collectionInterval
	conf.DisableDispatchedJobSummaryMetrics = agentConfig.Telemetry.DisableDispatchedJobSummaryMetrics
	conf.DisableQuotaUtilizationMetrics = agentConfig.Telemetry.DisableQuotaUtilizationMetrics
	conf.DisableRPCRateMetricsLabels = agentConfig.Telemetry.DisableRPCRateMetricsLabels

	if d, err := time.ParseDuration(agentConfig.Limits.RPCHandshakeTimeout); err != nil {
		return nil, fmt.Errorf("error parsing rpc_handshake_timeout: %v", err)
	} else if d < 0 {
		return nil, fmt.Errorf("rpc_handshake_timeout must be >= 0")
	} else {
		conf.RPCHandshakeTimeout = d
	}

	// Set max rpc conns; nil/0 == unlimited
	// Leave a little room for streaming RPCs
	minLimit := config.LimitsNonStreamingConnsPerClient + 5
	if agentConfig.Limits.RPCMaxConnsPerClient == nil || *agentConfig.Limits.RPCMaxConnsPerClient == 0 {
		conf.RPCMaxConnsPerClient = 0
	} else if limit := *agentConfig.Limits.RPCMaxConnsPerClient; limit <= minLimit {
		return nil, fmt.Errorf("rpc_max_conns_per_client must be > %d; found: %d", minLimit, limit)
	} else {
		conf.RPCMaxConnsPerClient = limit
	}

	// Set deployment rate limit
	if rate := agentConfig.Server.DeploymentQueryRateLimit; rate == 0 {
		conf.DeploymentQueryRateLimit = deploymentwatcher.LimitStateQueriesPerSecond

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set a non-negative duration, e.g. rpc_handshake_timeout = "5s"
  2. Remove the setting to use Nomad's default handshake timeout
  3. If you wanted to disable the limit, check Nomad docs for the supported mechanism instead of using a negative value
  4. Fix any template/variable producing a negative number

Example fix

// before
limits {
  rpc_handshake_timeout = "-1s"
}
// after
limits {
  rpc_handshake_timeout = "5s"
}
Defensive patterns

Strategy: validation

Validate before calling

// Go: reject negative durations before applying config
d, err := time.ParseDuration(cfg.Limits.RPCHandshakeTimeout)
if err != nil || d < 0 {
    return errors.New("rpc_handshake_timeout must be a non-negative duration")
}

Type guard

func isNonNegativeDuration(s string) bool {
    d, err := time.ParseDuration(s)
    return err == nil && d >= 0
}

Prevention

When it happens

Trigger: Setting limits { rpc_handshake_timeout = "-1s" } (or any negative duration) in the server agent config and starting the agent, or applying it via a reload handled by handleReload.

Common situations: Operators trying to 'disable' the timeout with a negative value; templated configs where an interpolated variable resolves to a negative number; copy-paste mistakes from tuning scripts.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/ceef56679436c8c5. Report an issue: GitHub.