hashicorp/nomad · error

error parsing rpc_handshake_timeout: %v

Error message

error parsing rpc_handshake_timeout: %v

What it means

The limits.rpc_handshake_timeout value is parsed with time.ParseDuration, which requires a Go duration string like "5s" or "500ms". If the value is absent-but-nonempty garbage or malformed (e.g. "5" with no unit, "five seconds"), ParseDuration fails and convertServerConfig returns this wrapped error, aborting agent startup or config reload.

Source

Thrown at command/agent/agent.go:596

		if agentConfig.RPC.StreamOpenTimeout > 0 {
			conf.RPCSessionConfig.StreamOpenTimeout = agentConfig.RPC.StreamOpenTimeout
		}
		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

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Change the value to a valid Go duration string with a unit, e.g. rpc_handshake_timeout = "5s"
  2. Remove the rpc_handshake_timeout line entirely to use the default
  3. Check for stray whitespace, quotes, or locale-formatted numbers in the config value
  4. Validate with nomad agent config / config validate before deploying if available

Example fix

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

Strategy: validation

Validate before calling

// Go: pre-validate duration strings before writing the config
func validDuration(s string) bool {
    _, err := time.ParseDuration(s)
    return s == "" || err == nil
}
// reject values like "5" early
if !validDuration(cfg.Limits.RPCHandshakeTimeout) { ... }

Type guard

func isGoDuration(s string) bool {
    _, err := time.ParseDuration(s)
    return err == nil
}

Try / catch

// wrap agent start to surface config errors clearly
conf, err := convertServerConfig(agentConfig)
if err != nil {
    return fmt.Errorf("server config invalid: %w", err)
}

Prevention

When it happens

Trigger: Setting limits { rpc_handshake_timeout = "5" } (missing unit), or any string that is not a valid Go duration (empty string, "5 sec", negative-looking typos like "-5s" handled separately by 1102) when starting or reloading a Nomad server.

Common situations: Users copying values from Prometheus/other tools that use plain numbers with implicit seconds; YAML/JSON configs where a numeric 5 gets stringified oddly; hand-edits adding the option without knowing Go duration syntax.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


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