hashicorp/nomad · error

error parsing rpc_handshake_timeout

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.

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.

Appendix: 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)