temporalio/temporal · error

invalid WorkflowRetryPolicy on StartChildWorkflowExecutionCo

Error message

invalid WorkflowRetryPolicy on StartChildWorkflowExecutionCommand: %w. WorkflowId=%s WorkflowType=%s Namespace=%s

What it means

ValidateStartChildExecutionAttributes rejects a StartChildWorkflowExecution command whose RetryPolicy fails validation in the child namespace context. The workflow task fails with this wrapped message identifying WorkflowId/Type/Namespace.

Source

Thrown at service/history/api/command_attr_validator.go:522

	if len(wfType) > v.maxIDLengthLimit {
		return failedCause, serviceerror.NewInvalidArgumentf("WorkflowType on StartChildWorkflowExecutionCommand exceeds length limit. WorkflowId=%s WorkflowType=%s Length=%d Limit=%d Namespace=%s", wfID, wfType, len(wfType), v.maxIDLengthLimit, ns)
	}

	if err := timestamp.ValidateAndCapProtoDuration(attributes.GetWorkflowExecutionTimeout()); err != nil {
		return failedCause, serviceerror.NewInvalidArgumentf("Invalid WorkflowExecutionTimeout on StartChildWorkflowExecutionCommand: %v. WorkflowId=%s WorkflowType=%s Namespace=%s", err, wfID, wfType, ns)
	}

	if err := timestamp.ValidateAndCapProtoDuration(attributes.GetWorkflowRunTimeout()); err != nil {
		return failedCause, serviceerror.NewInvalidArgumentf("Invalid WorkflowRunTimeout on StartChildWorkflowExecutionCommand: %v. WorkflowId=%s WorkflowType=%s Namespace=%s", err, wfID, wfType, ns)
	}

	if err := timestamp.ValidateAndCapProtoDuration(attributes.GetWorkflowTaskTimeout()); err != nil {
		return failedCause, serviceerror.NewInvalidArgumentf("Invalid WorkflowTaskTimeout on StartChildWorkflowExecutionCommand: %v. WorkflowId=%s WorkflowType=%s Namespace=%s", err, wfID, wfType, ns)
	}

	if err := v.validateWorkflowRetryPolicy(namespace.Name(attributes.GetNamespace()), attributes.RetryPolicy); err != nil {
		return failedCause, fmt.Errorf("invalid WorkflowRetryPolicy on StartChildWorkflowExecutionCommand: %w. WorkflowId=%s WorkflowType=%s Namespace=%s", err, wfID, wfType, ns)
	}

	if err := backoff.ValidateSchedule(attributes.GetCronSchedule()); err != nil {
		return failedCause, fmt.Errorf("invalid CronSchedule on StartChildWorkflowExecutionCommand: %w. WorkflowId=%s WorkflowType=%s Namespace=%s", err, wfID, wfType, ns)
	}

	if err := v.searchAttributesValidator.Validate(attributes.GetSearchAttributes(), targetNamespace.String()); err != nil {
		return enumspb.WORKFLOW_TASK_FAILED_CAUSE_BAD_SEARCH_ATTRIBUTES, fmt.Errorf("invalid SearchAttributes on StartChildWorkflowCommand: %w. WorkflowId=%s WorkflowType=%s Namespace=%s", err, wfID, wfType, ns)
	}

	if err := priorities.Validate(attributes.Priority); err != nil {
		return failedCause, err
	}

	// Inherit taskqueue from parent workflow execution if not provided on command
	if attributes.TaskQueue == nil {
		attributes.TaskQueue = &taskqueuepb.TaskQueue{
			Kind: enumspb.TASK_QUEUE_KIND_NORMAL,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Fix RetryPolicy values: InitialInterval > 0, coefficient >= 1, MaximumInterval >= InitialInterval
  2. Use SDK default retry policy helpers
  3. Validate the policy before starting the child workflow

Example fix

// before
opts := workflow.ChildWorkflowOptions{RetryPolicy: &workflowsvc.RetryPolicy{BackoffCoefficient: 0.5}}
// after
opts := workflow.ChildWorkflowOptions{RetryPolicy: &workflowsvc.RetryPolicy{InitialInterval: durationpb.New(time.Second), BackoffCoefficient: 2}}
Defensive patterns

Strategy: validation

Validate before calling

func validChildRetry(p *workflowsvc.RetryPolicy) bool { return p == nil || (p.GetInitialInterval().AsDuration() > 0 && p.GetBackoffCoefficient() >= 1) }

Type guard

func retryPolicyFromOptions(o workflow.ChildWorkflowOptions) *workflowsvc.RetryPolicy { return o.RetryPolicy }

Try / catch

child workflow start fails as workflow task failure; check child workflow history for the StartChildWorkflowExecutionCommandFailed event

Prevention

When it happens

Trigger: ChildWorkflowOptions with an invalid RetryPolicy (non-positive InitialInterval, BackoffCoefficient < 1, MaximumInterval < InitialInterval) when the parent issues the StartChildWorkflowExecution command.

Common situations: Unit mistakes in retry intervals (ms/s); serializing a zero-value struct as if it were a full policy; cross-namespace children inheriting policies that don't validate in the target namespace.

Related errors


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