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 errView on GitHub (pinned to bde624efd1)
Solutions
- Ensure the version workflow is started through the WorkerDeployment client APIs which populate VersionState
- If hit after an upgrade on an old workflow, let it fail and continue-as-new / recreate the version workflow
- 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
- Always start version workflows via supported Worker Deployment APIs, never directly
- After server upgrades, watch for legacy version workflows lacking initialized state
- Report persistent occurrences with workflow history — it signals corrupted state
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
- failed to read version demotion signal configuration: %w
- ${failure.Message}
- task queue user data replication failed: %v
- invalid schedule: %s
- Unknown cluster name: %v with given cluster initial failover
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/b5ff30c6e30cd9b6.
Report an issue: GitHub.