temporalio/temporal · error

batchParams is nil

Error message

batchParams is nil

What it means

BatchWorkflowProtobuf is the entry workflow for batch operations (reset, terminate, signal, delete-namespace) and expects its input as a *batchspb.BatchOperationInput serialized in the workflow start payload. If the parameter is nil — the workflow was started with no input, a nil payload, or an older/incorrect input type — it immediately fails with this error since no batch can run without parameters.

Source

Thrown at service/worker/batcher/workflow.go:140

var (
	batchActivityRetryPolicy = temporal.RetryPolicy{
		InitialInterval:    10 * time.Second,
		BackoffCoefficient: 1.7,
		MaximumInterval:    5 * time.Minute,
	}

	batchActivityOptions = workflow.ActivityOptions{
		ScheduleToStartTimeout: 5 * time.Minute,
		StartToCloseTimeout:    infiniteDuration,
		RetryPolicy:            &batchActivityRetryPolicy,
	}
)

// BatchWorkflowProtobuf is the workflow that runs a batch job of resetting workflows.
func BatchWorkflowProtobuf(ctx workflow.Context, batchParams *batchspb.BatchOperationInput) (HeartBeatDetails, error) {
	if batchParams == nil {
		return HeartBeatDetails{}, errors.New("batchParams is nil")
	}

	batchParams = setDefaultParams(batchParams)
	batchActivityOptions.HeartbeatTimeout = batchParams.ActivityHeartbeatTimeout.AsDuration()
	opt := workflow.WithActivityOptions(ctx, batchActivityOptions)
	var result HeartBeatDetails
	var ac *activities
	err := workflow.ExecuteActivity(opt, ac.BatchActivityWithProtobuf, batchParams).Get(ctx, &result)
	if err != nil {
		return HeartBeatDetails{}, err
	}

	err = attachBatchOperationStats(ctx, result)
	if err != nil {
		return HeartBeatDetails{}, err
	}
	return result, err
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Start the batch operation through the CLI (`temporal batch ...`) or SDK helper that serializes BatchOperationInput correctly.
  2. Verify the input payload is present and of type batchspb.BatchOperationInput when starting the workflow manually.
  3. Check CLI/server version compatibility — old CLIs may omit fields newer workflow code expects.
  4. If it's a genuine bug path, treat the nil check as a precondition and fix the caller that starts the workflow without input.

Example fix

// before
temporalClient.ExecuteWorkflow(ctx, opts, batcher.BatchWorkflowProtobuf, nil)
// after
input := &batchspb.BatchOperationInput{
	Query: "ExecutionStatus = \"Running\"",
	Operation: &batchspb.BatchOperationInput_ResetOperation{...},
}
temporalClient.ExecuteWorkflow(ctx, opts, batcher.BatchWorkflowProtobuf, input)
Defensive patterns

Strategy: validation

Validate before calling

if batchParams == nil || batchParams.Operation == nil {
	return fmt.Errorf("batch operation input must be a non-nil batchspb.BatchOperationInput with an operation")
}

Type guard

func isValidBatchInput(p *batchspb.BatchOperationInput) bool {
	return p != nil && p.Operation != nil
}

Try / catch

wf, err := temporalClient.ExecuteWorkflow(ctx, opts, batcher.BatchWorkflowProtobuf, input)
if err != nil {
	// input serialization failure or immediate validation error like "batchParams is nil"
}

Prevention

When it happens

Trigger: Starting the batch workflow (BatchWorkflowProtobuf / temporal batch operations) with an empty or malformed input payload, or programmatically executing the workflow passing nil for batchParams.

Common situations: Calling temporal batch operations against a server/CLI version mismatch where the input proto isn't populated; hand-crafted workflow start via SDK with wrong input type; replaying old executions with a different input encoding.

Related errors


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