{"record":{"id":"9837c52be482354c","repo":"temporalio/temporal","slug":"decoding-workerdeploymentmemo-failed-memo-or-it-s","errorCode":null,"errorMessage":"decoding WorkerDeploymentMemo failed: Memo or it's fields are nil","messagePattern":"decoding WorkerDeploymentMemo failed: Memo or it's fields are nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/worker/workerdeployment/util.go","lineNumber":170,"sourceCode":"// GenerateDeploymentWorkflowID is a helper that generates a system accepted\n// workflowID which are used in our Worker Deployment workflows\nfunc GenerateDeploymentWorkflowID(deploymentName string) string {\n\treturn worker_versioning.WorkerDeploymentWorkflowIDPrefix + worker_versioning.WorkerDeploymentVersionDelimiter + deploymentName\n}\n\n// GenerateVersionWorkflowID is a helper that generates a system accepted\n// workflowID which are used in our Worker Deployment Version workflows\nfunc GenerateVersionWorkflowID(deploymentName string, buildID string) string {\n\tversionString := worker_versioning.ExternalWorkerDeploymentVersionToString(&deploymentpb.WorkerDeploymentVersion{\n\t\tDeploymentName: deploymentName,\n\t\tBuildId:        buildID,\n\t})\n\treturn worker_versioning.WorkerDeploymentVersionWorkflowIDPrefix + worker_versioning.WorkerDeploymentVersionDelimiter + versionString\n}\n\nfunc DecodeWorkerDeploymentMemo(memo *commonpb.Memo) (*deploymentspb.WorkerDeploymentWorkflowMemo, error) {\n\tif memo == nil || memo.Fields == nil {\n\t\treturn nil, errors.New(\"decoding WorkerDeploymentMemo failed: Memo or it's fields are nil\")\n\t}\n\tvar workerDeploymentWorkflowMemo deploymentspb.WorkerDeploymentWorkflowMemo\n\terr := sdk.PreferProtoDataConverter.FromPayload(memo.Fields[WorkerDeploymentMemoField], &workerDeploymentWorkflowMemo)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &workerDeploymentWorkflowMemo, nil\n}\n\nfunc getSafeDurationConfig(ctx workflow.Context, id string, unsafeGetter func() time.Duration, defaultValue time.Duration) (time.Duration, error) {\n\tget := func(_ workflow.Context) any {\n\t\treturn unsafeGetter()\n\t}\n\tvar value time.Duration\n\tif err := workflow.MutableSideEffect(ctx, id, get, durationEq).Get(&value); err != nil {\n\t\treturn defaultValue, err\n\t}\n\treturn value, nil","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/workerdeployment/util.go#L152-L188","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nmemo, _ := resp.GetWorkflowExecutionInfo().GetMemo(), nil\ndeploymentMemo, err := workerdeployment.DecodeWorkerDeploymentMemo(memo)\n// after\ninfo := resp.GetWorkflowExecutionInfo()\nif info.GetMemo() == nil || info.GetMemo().GetFields()[workerdeployment.WorkerDeploymentMemoField] == nil {\n    return errors.New(\"deployment workflow has no deployment memo; it may have been created by an incompatible client\")\n}\ndeploymentMemo, err := workerdeployment.DecodeWorkerDeploymentMemo(info.GetMemo())","handlingStrategy":"validation","validationCode":"func hasDeploymentMemo(memo *commonpb.Memo) bool {\n    return memo != nil && memo.GetFields()[workerdeployment.WorkerDeploymentMemoField] != nil\n}\n// call DecodeWorkerDeploymentMemo only if hasDeploymentMemo(memo)","typeGuard":"func safeDecode(memo *commonpb.Memo) (*deploymentspb.WorkerDeploymentWorkflowMemo, error) {\n    if memo == nil || memo.GetFields() == nil {\n        return nil, errors.New(\"memo is nil; deployment workflow may predate memo support\")\n    }\n    return workerdeployment.DecodeWorkerDeploymentMemo(memo)\n}","tryCatchPattern":"memo, err := decode(m)\nif err != nil {\n    if strings.Contains(err.Error(), \"Memo or it's fields are nil\") {\n        return handleMissingMemo(m) // fallback path\n    }\n    return err\n}","preventionTips":["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"],"tags":["worker-deployments","memo","proto-decoding","temporal"],"backgroundTag":"worker-deployment-memo-missing","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}