temporalio/temporal · error
panic(rec)
Error message
panic(rec)
What it means
In NDC WorkflowStateReplicator.Apply, a deferred recover() handler releases the versioned-transition artifact lock with errPanic semantics and then re-panics with panic(rec) to preserve the original panic. The re-panic is intentional: the lock must be released with the panic error before the panic propagates upward.
Source
Thrown at service/history/ndc/workflow_state_replicator.go:300
if err != nil {
return err
}
if emitLifecycle {
// Snapshot the post-apply mutable state at release time: the only point that is both after
// the apply (which mutates ms in place) and still under the workflow lock, since the apply
// releases via the transaction manager.
innerReleaseFn := releaseFn
releaseFn = func(err error) {
if err == nil && appliedMS == nil && ms != nil {
appliedMS = ms.CloneToProto()
}
innerReleaseFn(err)
}
}
defer func() {
if rec := recover(); rec != nil {
releaseFn(errPanic)
panic(rec)
}
releaseFn(retError)
}()
if versionedTransitionArtifact.IsFirstSync {
// this is the first replication task for this workflow
// TODO: Handle reset case to reduce the amount of history events write
continueProcess, err := r.handleFirstReplicationTask(ctx, archetypeID, wfCtx, versionedTransitionArtifact, sourceClusterName, captureMutableState)
if err != nil || !continueProcess {
return err
}
}
ms, err = wfCtx.LoadMutableState(ctx, r.shardContext)
switch err.(type) {
case *serviceerror.NotFound:
return r.applySnapshot(ctx, namespaceID, wid, rid, archetypeID, wfCtx, releaseFn, nil, versionedTransitionArtifact, sourceClusterName, captureMutableState)
case nil:
localTransitionHistory := ms.GetExecutionInfo().TransitionHistoryView on GitHub (pinned to bde624efd1)
Solutions
- Inspect the panic stack trace above this frame to find the real panicking code and fix that bug.
- Add validation/nil checks in the replication path that produced the nil/invalid value.
- Reproduce with the offending replication task payload in a unit/integration test.
Defensive patterns
Strategy: try-catch
Try / catch
defer func() {
if rec := recover(); rec != nil {
logger.Error("replication panic", "stack", string(debug.Stack()))
panic(rec)
}
}() Prevention
- Nil-check mutable state and workflow contexts in the replication apply path.
- Reproduce with a unit test before deploying replication changes.
When it happens
Trigger: Any code inside Apply's critical section panics (nil pointer on mutable state, invariant violation, index-out-of-range), triggering the deferred recover-and-repanic block.
Common situations: Corrupt or partially-loaded mutable state during replication; nil dereference on missing workflow context; bugs in replication task handling surfacing as panics.
Related errors
- Empty cluster information
- Master cluster name is empty
- Cannot set current time for current cluster
- corrupted history event batch, eventID is not contiguous
- history is nil
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/15a3b135fb8f8c26.
Report an issue: GitHub.