{"record":{"id":"3b944d0ece5f8cdb","repo":"temporalio/temporal","slug":"worker-deployment-deleted","errorCode":null,"errorMessage":"worker deployment deleted","messagePattern":"worker deployment deleted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"service/worker/workerdeployment/workflow.go","lineNumber":319,"sourceCode":"\n\t\td.metrics.Counter(metrics.WorkerDeploymentCreated.Name()).Inc(1)\n\t}\n\tif d.State.Versions == nil {\n\t\td.State.Versions = make(map[string]*deploymentspb.WorkerDeploymentVersionSummary)\n\t}\n\n\t// TODO(carlydf): remove verbose logging\n\td.logger.Info(\"Starting workflow run\",\n\t\t\"create_time\", d.State.GetCreateTime(),\n\t\t\"routing_config\", d.State.GetRoutingConfig(),\n\t\t//nolint:staticcheck // SA1019: worker versioning v0.31\n\t\t\"current_version\", d.State.GetRoutingConfig().GetCurrentVersion(),\n\t\t//nolint:staticcheck // SA1019: worker versioning v0.31\n\t\t\"ramping_version\", d.State.GetRoutingConfig().GetRampingVersion())\n\n\terr := workflow.SetQueryHandler(ctx, QueryDescribeDeployment, func() (*deploymentspb.QueryDescribeWorkerDeploymentResponse, error) {\n\t\tif d.deleteDeployment {\n\t\t\treturn nil, errors.New(errDeploymentDeleted)\n\t\t}\n\t\treturn &deploymentspb.QueryDescribeWorkerDeploymentResponse{\n\t\t\tState: d.State,\n\t\t}, nil\n\t})\n\tif err != nil {\n\t\td.logger.Info(\"SetQueryHandler failed for WorkerDeployment workflow with error: \" + err.Error())\n\t\treturn err\n\t}\n\n\terr = workflow.SetQueryHandler(ctx, QueryCreateRequestID, func() (*deploymentspb.CreateRequestIDQueryResponse, error) {\n\t\tif d.deleteDeployment {\n\t\t\treturn nil, errors.New(errDeploymentDeleted)\n\t\t}\n\t\treturn &deploymentspb.CreateRequestIDQueryResponse{\n\t\t\tRequestId:     d.GetState().GetCreateRequestId(),\n\t\t\tConflictToken: d.State.GetConflictToken(),\n\t\t}, nil","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/workerdeployment/workflow.go#L301-L337","documentation":"The Worker Deployment workflow registers a DescribeDeployment query handler; if the deployment has been marked deleted (d.deleteDeployment set), the handler returns errDeploymentDeleted instead of state. This tells callers the deployment workflow is draining/destroyed and no longer serves its state.","triggerScenarios":"Sending the DescribeDeployment query to a deployment workflow after a delete of the deployment was processed (d.deleteDeployment == true), e.g. via DescribeWorkerDeployment while the workflow is still finishing shutdown.","commonSituations":"Describing a deployment right after deleting it; automation that lists deployments and immediately describes each (TOCTOU race); polling loops that keep describing a deleted deployment until the workflow record disappears.","solutions":["Stop describing the deployment once it is deleted; treat this error as confirmation of deletion","Filter out deleted deployments before describing (check deployment state via list APIs first)","In polling code, break the loop when this error is returned instead of retrying","If the deployment should not be deleted, audit recent DeleteWorkerDeployment calls / bad deploy automation"],"exampleFix":"// before\nfor _, name := range deployments {\n    d, err := client.DescribeWorkerDeployment(ctx, ns, name)\n    use(d)\n}\n// after\nfor _, name := range deployments {\n    d, err := client.DescribeWorkerDeployment(ctx, ns, name)\n    if err != nil && strings.Contains(err.Error(), \"worker deployment deleted\") {\n        continue // deleted; workflow is shutting down\n    }\n    use(d)\n}","handlingStrategy":"type-guard","validationCode":"// skip deployments already known to be deleted\nif deletedDeployments[name] { continue }\n// or inspect list output before describing","typeGuard":"func isDeploymentDeletedErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"worker deployment deleted\")\n}","tryCatchPattern":"d, err := client.DescribeWorkerDeployment(ctx, ns, name)\nif isDeploymentDeletedErr(err) {\n    log.Printf(\"deployment %s deleted, skipping\", name)\n    return nil\n}\nif err != nil { return err }","preventionTips":["Never assume a listed deployment is still live by the time you describe it","Audit automation that deletes deployments to avoid races with describe calls","Centralize deployment error classification (deleted vs transient) in one helper"],"tags":["worker-deployments","query","deleted-deployment","temporal"],"backgroundTag":"entity-already-deleted","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}