hashicorp/nomad · error

failed to parse start_timeout: %v

Error message

failed to parse start_timeout: %v

What it means

convertServerConfig parses server.start_timeout with time.ParseDuration and rejects it if unparsable or non-positive ("start_timeout should be greater than 0s" follows immediately for the latter). This timeout bounds how long the server waits during startup; an invalid value would silently disable or break that bound, so it fails fast.

Source

Thrown at command/agent/agent.go:719

	if agentConfig.Server.JobMaxSourceSize == nil {
		agentConfig.Server.JobMaxSourceSize = new("1M")
	}
	jobMaxSourceBytes, err := humanize.ParseBytes(*agentConfig.Server.JobMaxSourceSize)
	if err != nil {
		return nil, fmt.Errorf("failed to parse max job source bytes: %w", err)
	}
	conf.JobMaxSourceSize = int(jobMaxSourceBytes)

	conf.Reporting = agentConfig.Reporting
	// Pass the server's production status through to the reporting config
	conf.Reporting.NonProduction = agentConfig.Server.NonProduction

	conf.KEKProviderConfigs = agentConfig.KEKProviders

	if startTimeout := agentConfig.Server.StartTimeout; startTimeout != "" {
		dur, err := time.ParseDuration(startTimeout)
		if err != nil {
			return nil, fmt.Errorf("failed to parse start_timeout: %v", err)
		} else if dur <= time.Duration(0) {
			return nil, fmt.Errorf("start_timeout should be greater than 0s")
		}
		conf.StartTimeout = dur
	}

	// Ensure the passed number of scheduler is between the bounds of zero and
	// the number of CPU cores on the machine. The runtime CPU count object is
	// populated at process start time, so there is no overhead in calling the
	// function compared to saving the value.
	if conf.NumSchedulers < 0 || conf.NumSchedulers > runtime.NumCPU() {
		return nil, fmt.Errorf("number of schedulers should be between 0 and %d",
			runtime.NumCPU())
	}

	// If the operator has specified a client introduction server config block,
	// translate this into the internal server configuration object.
	if agentConfig.Server.ClientIntroduction != nil {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set start_timeout to a positive Go duration with a unit, e.g. start_timeout = "30s".
  2. Ensure zero/negative values are replaced with a positive duration (0 is explicitly rejected).
  3. If a variable feeds this field, render and `nomad validate` the config to confirm the final value.
  4. Remove the key to accept the default timeout if no custom value is required.

Example fix

// before
server {
  start_timeout = "0s"
}
// after
server {
  start_timeout = "30s"
}
Defensive patterns

Strategy: validation

Validate before calling

d, err := time.ParseDuration(startTimeout)
if err != nil {
    return fmt.Errorf("start_timeout %q is not a valid Go duration: %v", startTimeout, err)
}
if d <= 0 {
    return fmt.Errorf("start_timeout must be > 0s")
}

Prevention

When it happens

Trigger: start_timeout set to a string time.ParseDuration rejects ("30", "5min", "half-minute") or to zero/negative after parsing ("0s", "-10s"). Triggered at agent start or SIGHUP reload through serverConfig/handleReload.

Common situations: Omitting the unit ("300" meaning seconds); using non-Go duration syntax like "5m30s" is fine but "5 minutes" is not; template injection producing "0s" or empty-adjacent values; operators trying to disable the timeout with 0 and hitting the positivity check.

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/2825bdf135c71ff3. Report an issue: GitHub.