temporalio/temporal · error

version cannot be nil on start

Error message

version cannot be nil on start

What it means

The worker deployment version workflow's run method requires VersionState.Version to be populated at start; if nil it returns this error, failing the workflow. It guards a core invariant — the workflow exists to manage a specific version, and its state should be initialized by VersionWorkflow before run executes.

Source

Thrown at service/worker/workerdeployment/version_workflow.go:253

			d.signalHandler.processingSignals++
			defer func() { d.signalHandler.processingSignals-- }()

			var vs wciiface.ValidationStatus
			c.Receive(ctx, &vs)
			d.VersionState.ComputeStatus = wciValidationStatusToComputeStatus(&vs)
			d.syncSummary(ctx) // propagate updated ComputeStatus to deployment workflow
		})
	}

	// Keep waiting for signals, when it's time to CaN the main goroutine will exit.
	for {
		d.signalHandler.signalSelector.Select(ctx)
	}
}

func (d *VersionWorkflowRunner) run(ctx workflow.Context) error {
	if d.GetVersionState().Version == nil {
		return fmt.Errorf("version cannot be nil on start")
	}
	if d.VersionState.GetCreateTime() == nil {
		d.VersionState.CreateTime = timestamppb.New(workflow.Now(ctx))
	}
	// TODO: remove this after next release because now the status should always be set at start.
	if d.VersionState.Status == enumspb.WORKER_DEPLOYMENT_VERSION_STATUS_UNSPECIFIED {
		d.VersionState.Status = enumspb.WORKER_DEPLOYMENT_VERSION_STATUS_INACTIVE
	}

	// if we were draining and just continued-as-new, do another drainage check after waiting for appropriate time
	if d.VersionState.GetDrainageInfo().GetStatus() == enumspb.VERSION_DRAINAGE_STATUS_DRAINING {
		workflow.Go(ctx, d.refreshDrainageInfo)
	}

	// Set up Query Handlers here:
	if err := workflow.SetQueryHandler(ctx, QueryDescribeVersion, d.handleDescribeQuery); err != nil {
		d.logger.Error("Failed while setting up query handler")
		return err

View on GitHub (pinned to bde624efd1)

Solutions

  1. Ensure the version workflow is started through the WorkerDeployment client APIs which populate VersionState
  2. If hit after an upgrade on an old workflow, let it fail and continue-as-new / recreate the version workflow
  3. Report as a bug with the workflow history if the version was provably passed at start — it is an invariant violation
Defensive patterns

Strategy: try-catch

Try / catch

err := workflow.ExecuteWorkflow(...VersionWorkflow...).Get(ctx, &out)
if err != nil && strings.Contains(err.Error(), "version cannot be nil on start") {
    // restart the version workflow through the deployment client APIs
}

Prevention

When it happens

Trigger: Starting VersionWorkflow with uninitialized state, e.g. after a malfunction in workflow construction, deserialization of an empty/legacy workflow state, or a bug where the version argument was never set.

Common situations: Temporal server/worker-deployment version upgrade where old workflows were created before state initialization was guaranteed; corrupted continue-as-new payloads; SDK-side misuse starting the workflow directly instead of via the deployment APIs.

Related errors


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