hashicorp/nomad · error

stdout_repeat_duration %v not a valid duration: %v

Error message

stdout_repeat_duration %v not a valid duration: %v

What it means

parseDurations also converts StdoutRepeatDur into stdoutRepeatDuration using parseDuration. A value time.ParseDuration (or the mock helper) cannot interpret makes the driver return 'stdout_repeat_duration %v not a valid duration: %v'. Called from RecoverTask and parseDriverConfig, so it blocks both recovery and start of the mock task.

Source

Thrown at drivers/mock/driver.go:416

		startedAt:       taskState.StartedAt,
		kill:            killCancel,
		killCh:          killCtx.Done(),
		Recovered:       true,
	}

	d.tasks.Set(handle.Config.ID, h)
	go h.run()
	return nil
}

func (c *Command) parseDurations() error {
	var err error
	if c.runForDuration, err = parseDuration(c.RunFor); err != nil {
		return fmt.Errorf("run_for %v not a valid duration: %v", c.RunFor, err)
	}

	if c.stdoutRepeatDuration, err = parseDuration(c.StdoutRepeatDur); err != nil {
		return fmt.Errorf("stdout_repeat_duration %v not a valid duration: %v", c.stdoutRepeatDuration, err)
	}

	if c.stderrRepeatDuration, err = parseDuration(c.StderrRepeatDur); err != nil {
		return fmt.Errorf("stderr_repeat_duration %v not a valid duration: %v", c.stderrRepeatDuration, err)
	}

	return nil
}

func parseDriverConfig(cfg *drivers.TaskConfig) (*TaskConfig, error) {
	var driverConfig TaskConfig
	if err := cfg.DecodeDriverConfig(&driverConfig); err != nil {
		return nil, err
	}

	var err error
	if driverConfig.startBlockForDuration, err = parseDuration(driverConfig.StartBlockFor); err != nil {
		return nil, fmt.Errorf("start_block_for %v not a valid duration: %v", driverConfig.StartBlockFor, err)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set stdout_repeat_duration to a valid Go duration string, e.g. "1s", "500ms", "0".
  2. Read the wrapped time.ParseDuration error to see the offending substring.
  3. Validate interpolated values before submitting the job (nomad job inspect / local validation).
  4. For recovery failures, resubmit the job with corrected config.

Example fix

// before
stdout_repeat_duration = "500"
// after
stdout_repeat_duration = "500ms"
Defensive patterns

Strategy: validation

Validate before calling

if _, err := time.ParseDuration(c.StdoutRepeatDur); err != nil {
    return fmt.Errorf("stdout_repeat_duration must be like 500ms, got %q", c.StdoutRepeatDur)
}

Type guard

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

Try / catch

if err := cmd.parseDurations(); err != nil {
    if strings.Contains(err.Error(), "stdout_repeat_duration") {
        return fmt.Errorf("fix stdout_repeat_duration in mock driver config: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Mock driver config sets stdout_repeat_duration to a malformed string (e.g. "100msx", "", "every 5s", "0.5") — RecoverTask or StartTask config parsing fails immediately.

Common situations: Copy-paste typos in job specs; forgetting the unit ("500" instead of "500ms"); interpolated env vars empty; locale-formatted numbers with commas.

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