temporalio/temporal · error
decoding WorkerDeploymentMemo failed: Memo or it's fields ar
Error message
decoding WorkerDeploymentMemo failed: Memo or it's fields are nil
What it means
DecodeWorkerDeploymentMemo converts the memo payload stored on a WorkerDeployment workflow into a deploymentspb.WorkerDeploymentWorkflowMemo struct. It rejects calls where the memo or its Fields map is nil because there is no protobuf payload to decode, returning this sentinel-style error. The error indicates the deployment workflow was created without the required memo field (WorkerDeploymentMemoField).
Source
Thrown at service/worker/workerdeployment/util.go:170
// GenerateDeploymentWorkflowID is a helper that generates a system accepted
// workflowID which are used in our Worker Deployment workflows
func GenerateDeploymentWorkflowID(deploymentName string) string {
return worker_versioning.WorkerDeploymentWorkflowIDPrefix + worker_versioning.WorkerDeploymentVersionDelimiter + deploymentName
}
// GenerateVersionWorkflowID is a helper that generates a system accepted
// workflowID which are used in our Worker Deployment Version workflows
func GenerateVersionWorkflowID(deploymentName string, buildID string) string {
versionString := worker_versioning.ExternalWorkerDeploymentVersionToString(&deploymentpb.WorkerDeploymentVersion{
DeploymentName: deploymentName,
BuildId: buildID,
})
return worker_versioning.WorkerDeploymentVersionWorkflowIDPrefix + worker_versioning.WorkerDeploymentVersionDelimiter + versionString
}
func DecodeWorkerDeploymentMemo(memo *commonpb.Memo) (*deploymentspb.WorkerDeploymentWorkflowMemo, error) {
if memo == nil || memo.Fields == nil {
return nil, errors.New("decoding WorkerDeploymentMemo failed: Memo or it's fields are nil")
}
var workerDeploymentWorkflowMemo deploymentspb.WorkerDeploymentWorkflowMemo
err := sdk.PreferProtoDataConverter.FromPayload(memo.Fields[WorkerDeploymentMemoField], &workerDeploymentWorkflowMemo)
if err != nil {
return nil, err
}
return &workerDeploymentWorkflowMemo, nil
}
func getSafeDurationConfig(ctx workflow.Context, id string, unsafeGetter func() time.Duration, defaultValue time.Duration) (time.Duration, error) {
get := func(_ workflow.Context) any {
return unsafeGetter()
}
var value time.Duration
if err := workflow.MutableSideEffect(ctx, id, get, durationEq).Get(&value); err != nil {
return defaultValue, err
}
return value, nilView on GitHub (pinned to bde624efd1)
Solutions
- Ensure the deployment workflow was created with a memo containing the WorkerDeploymentMemoField key before describing/decoding
- Check the memo key matches the exported WorkerDeploymentMemoField constant (schema/version drift between writers and readers)
- Nil-check memo and fields at the call site and surface a friendlier message, or fall back to a default empty memo struct
- If the deployment is corrupt/legacy, recreate the deployment version with a current SDK/CLI
Example fix
// before
memo, _ := resp.GetWorkflowExecutionInfo().GetMemo(), nil
deploymentMemo, err := workerdeployment.DecodeWorkerDeploymentMemo(memo)
// after
info := resp.GetWorkflowExecutionInfo()
if info.GetMemo() == nil || info.GetMemo().GetFields()[workerdeployment.WorkerDeploymentMemoField] == nil {
return errors.New("deployment workflow has no deployment memo; it may have been created by an incompatible client")
}
deploymentMemo, err := workerdeployment.DecodeWorkerDeploymentMemo(info.GetMemo()) Defensive patterns
Strategy: validation
Validate before calling
func hasDeploymentMemo(memo *commonpb.Memo) bool {
return memo != nil && memo.GetFields()[workerdeployment.WorkerDeploymentMemoField] != nil
}
// call DecodeWorkerDeploymentMemo only if hasDeploymentMemo(memo) Type guard
func safeDecode(memo *commonpb.Memo) (*deploymentspb.WorkerDeploymentWorkflowMemo, error) {
if memo == nil || memo.GetFields() == nil {
return nil, errors.New("memo is nil; deployment workflow may predate memo support")
}
return workerdeployment.DecodeWorkerDeploymentMemo(memo)
} Try / catch
memo, err := decode(m)
if err != nil {
if strings.Contains(err.Error(), "Memo or it's fields are nil") {
return handleMissingMemo(m) // fallback path
}
return err
} Prevention
- Always create worker deployment workflows through SDK/CLI paths that set the deployment memo
- Assert memo presence in tests that construct deployment workflows
- Version-gate: refuse to operate on deployments created before memo support
When it happens
Trigger: Calling DecodeWorkerDeploymentMemo with a nil *commonpb.Memo, or a Memo whose Fields map is nil/empty — e.g. the memo fetched via DescribeWorkflowExecution for a deployment whose workflow was started without a memo, or with the wrong memo key.
Common situations: Deployments created by older SDKs or CLI paths that did not set the WorkerDeploymentMemoField memo; user-modified workflow memos; describing a deployment right after a failed create; tests constructing workflows without memos.
Related errors
- worker deployment version deleted
- worker deployment deleted
- batch operation stats are not present in the memo
- %w: ref transition count out of range for version %v: %v not
- unknown archetypeID: %v
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/9837c52be482354c.
Report an issue: GitHub.