temporalio/temporal · error

errInvalidWorkflowRunTimeoutSeconds

errInvalidWorkflowRunTimeoutSeconds

Error message

%w cause: %v

What it means

Same validation pattern as the execution timeout, applied to WorkflowRunTimeout: timestamp.ValidateAndCapProtoDuration rejects invalid values and the validator wraps the cause with errInvalidWorkflowRunTimeoutSeconds. Run timeouts must be valid, positive, whole-second durations within the server cap.

Source

Thrown at chasm/lib/workflow/validator.go:77

	}
	return nil
}

type StartWorkflowTimeoutLikeRequest interface {
	GetWorkflowExecutionTimeout() *durationpb.Duration
	GetWorkflowRunTimeout() *durationpb.Duration
	GetWorkflowTaskTimeout() *durationpb.Duration
}

func (v *RequestValidator) ValidateWorkflowTimeouts(
	request StartWorkflowTimeoutLikeRequest,
) error {
	if err := timestamp.ValidateAndCapProtoDuration(request.GetWorkflowExecutionTimeout()); err != nil {
		return fmt.Errorf("%w cause: %v", errInvalidWorkflowExecutionTimeoutSeconds, err)
	}

	if err := timestamp.ValidateAndCapProtoDuration(request.GetWorkflowRunTimeout()); err != nil {
		return fmt.Errorf("%w cause: %v", errInvalidWorkflowRunTimeoutSeconds, err)
	}

	if err := timestamp.ValidateAndCapProtoDuration(request.GetWorkflowTaskTimeout()); err != nil {
		return fmt.Errorf("%w cause: %v", errInvalidWorkflowTaskTimeoutSeconds, err)
	}

	return nil
}

func (v *RequestValidator) ValidateRetryPolicy(namespaceName string, retryPolicy *commonpb.RetryPolicy) error {
	if retryPolicy == nil {
		// By default, if the user does not explicitly set a retry policy for a Workflow, do not perform any retries.
		return nil
	}

	retrypolicy.EnsureDefaults(retryPolicy, v.config.defaultWorkflowRetrySettings(namespaceName))
	return retrypolicy.Validate(retryPolicy)
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Set WorkflowRunTimeout to a positive whole-seconds duration within the cap, or leave it unset to inherit execution timeout
  2. Audit client duration math to avoid sub-second or negative values
  3. Verify server-side timeout cap dynamic config; raise it or lower the requested value

Example fix

// before
req.WorkflowRunTimeout = durationpb.New(1500 * time.Millisecond)
// after
req.WorkflowRunTimeout = durationpb.New(2 * time.Second)
Defensive patterns

Strategy: validation

Validate before calling

func validRunTimeout(d *durationpb.Duration) bool {
    if d == nil { return true }
    dur := d.AsDuration()
    return dur > 0 && dur%time.Second == 0
}
// call before StartWorkflowExecution / SignalWithStart:
if !validRunTimeout(req.WorkflowRunTimeout) { /* fix or clear field */ }

Try / catch

// Go
if err := validator.ValidateWorkflowTimeouts(req); err != nil {
    if errors.Is(err, errInvalidWorkflowRunTimeoutSeconds) {
        return status.Errorf(codes.InvalidArgument, "run timeout: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling StartWorkflowExecution or SignalWithStart (through ValidateSignalWithStartRequest) with request.WorkflowRunTimeout negative, sub-second, or exceeding the configured maximum.

Common situations: Passing a time.Duration computed from milliseconds (e.g. 1500ms) which fails the whole-seconds validation; negative values from clock/deadline math bugs; exceeding operator-configured timeout caps after a server config change.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/1adadb021f20ce62. Report an issue: GitHub.