Protect against decode errors in list worker deployments (#8985)

## What changed?
Changed `DecodeWorkerDeploymentMemo` to return an error instead of nil
on decode failures. Added error handling in `ListWorkerDeployments` to
log and skip deployments with corrupted memos.

## Why?
Production nil pointer panic at client.go:610 when
`DecodeWorkerDeploymentMemo` silently returned nil on decode errors.
Previously only checked if memo exists, not if decode succeeded.

## How did you test it?
- [x] built
- [ ] run locally and tested manually
- [ ] covered by existing tests
- [ ] added new unit test(s)
- [ ] added new functional test(s)

## Potential risks
List operations will silently skip deployments with malformed memos
instead of failing the entire request. Error is logged for debugging.
This commit is contained in:
Sean Kane
2026-01-09 16:53:01 +00:00
committed by GitHub
parent a6e4215fb6
commit 412c33aaab
2 changed files with 11 additions and 4 deletions
+5 -1
View File
@@ -595,7 +595,11 @@ func (d *ClientImpl) ListWorkerDeployments(
for i, ex := range persistenceResp.Executions {
var workerDeploymentInfo *deploymentspb.WorkerDeploymentWorkflowMemo
if ex.GetMemo() != nil {
workerDeploymentInfo = DecodeWorkerDeploymentMemo(ex.GetMemo())
workerDeploymentInfo, err = DecodeWorkerDeploymentMemo(ex.GetMemo())
if err != nil {
d.logger.Error("unable to decode worker deployment memo", tag.Error(err), tag.WorkflowNamespace(namespaceEntry.Name().String()), tag.WorkflowID(ex.GetExecution().GetWorkflowId()))
continue
}
} else {
// There is a race condition where the Deployment workflow exists, but has not yet
// upserted the memo. If that is the case, we handle it here.
+6 -3
View File
@@ -150,13 +150,16 @@ func GenerateVersionWorkflowID(deploymentName string, buildID string) string {
return worker_versioning.WorkerDeploymentVersionWorkflowIDPrefix + worker_versioning.WorkerDeploymentVersionDelimiter + versionString
}
func DecodeWorkerDeploymentMemo(memo *commonpb.Memo) *deploymentspb.WorkerDeploymentWorkflowMemo {
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
return nil, err
}
return &workerDeploymentWorkflowMemo
return &workerDeploymentWorkflowMemo, nil
}
func getSafeDurationConfig(ctx workflow.Context, id string, unsafeGetter func() time.Duration, defaultValue time.Duration) (time.Duration, error) {