{"record":{"id":"756f77d5fb6d2cf3","repo":"temporalio/temporal","slug":"re-panicked-recovered-value","errorCode":null,"errorMessage":"<re-panicked recovered value>","messagePattern":"<re-panicked recovered value>","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"chasm/tree.go","lineNumber":3651,"sourceCode":"\t\t\t}\n\t\t}\n\t\tif logicalTask == nil {\n\t\t\treturn false, false, nil\n\t\t}\n\t}\n\n\t// All structural checks passed — the task exists in the tree.\n\n\t// Component must be hydrated before the task's validator is called.\n\tvalidateCtx := NewContext(NewContextWithOperationIntent(ctx, OperationIntentProgress), n)\n\tif err := node.prepareComponentValue(validateCtx); err != nil {\n\t\treturn false, false, err\n\t}\n\n\tdefer func() {\n\t\tif rec := recover(); rec != nil {\n\t\t\tchasmTask.DeserializedTask = reflect.Value{}\n\t\t\tpanic(rec) //nolint:forbidigo\n\t\t}\n\t\tif retErr != nil {\n\t\t\tchasmTask.DeserializedTask = reflect.Value{}\n\t\t}\n\t}()\n\n\tif !chasmTask.DeserializedTask.IsValid() {\n\t\tvar err error\n\t\tif logicalTask != nil {\n\t\t\t// Use the logical task's Data pointer so deserialization shares the\n\t\t\t// node's taskValueCache with closeTransactionCleanupInvalidTasks.\n\t\t\t// The physical task's taskInfo.Data is a different pointer (freshly\n\t\t\t// allocated from the physical task row) and would always miss the cache.\n\t\t\tchasmTask.DeserializedTask, err = node.deserializeTaskWithCache(registrableTask, logicalTask.Data)\n\t\t} else {\n\t\t\t// Backward compatibility: physical task predates TaskVersionedTransition.\n\t\t\tchasmTask.DeserializedTask, err = deserializeTask(registrableTask, taskInfo.Data)\n\t\t}","sourceCodeStart":3633,"sourceCodeEnd":3669,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/chasm/tree.go#L3633-L3669","documentation":"This is a re-panic guard inside the CHASM side-effect task execution path (tree.go). A deferred recover() checks for a panic raised while the task (validator/execute) runs; before re-panicking it clears chasmTask.DeserializedTask so the deserialization cache doesn't retain a stale reflect.Value around the panicking call. The visible message is the original recovered value being re-thrown — the panic itself originates from user task code or framework internals, and this frame only preserves it while cleaning up cache state.","triggerScenarios":"Any panic inside the side-effect task's Validate or Execute invocation (after hydration, within the deferred-recover scope) — e.g. nil map write, index out of range, or explicit panic in user-registered CHASM task code.","commonSituations":"User CHASM task implementations panicking on unexpected input (nil derefs, failed type assertions); framework deserialization producing an invalid value that user code then misuses; panics in validators during task rehydration from persistence.","solutions":["Look below this frame in the stack trace for the original panic in task Validate/Execute code and fix that root cause","Add defensive checks in the task implementation for nil values and failed type assertions before using deserialized data","Verify the component's data payloads in persistence are compatible with the current struct definitions (schema drift can cause invalid values)","If the panic is inside framework code, report with the full stack trace"],"exampleFix":"// before\nfunc (t *MyTask) Execute(ctx chasm.Context, c *Component) (Result, error) {\n  return c.Order.Status.Value, nil // panics if Order is nil\n}\n// after\nfunc (t *MyTask) Execute(ctx chasm.Context, c *Component) (Result, error) {\n  if c == nil || c.Order == nil {\n    return Result{}, errors.New(\"order not initialized\")\n  }\n  return c.Order.Status.Value, nil\n}","handlingStrategy":"try-catch","validationCode":"// defensively validate deserialized inputs inside task code before use\nif task == nil || !task.Payload.IsValid() {\n    return errors.New(\"invalid task payload\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        logger.Error(\"panic in chasm task\", \"recover\", r, \"stack\", debug.Stack())\n        // convert to error return where the task API allows\n    }\n}()","preventionTips":["Write nil-safe, assertion-safe CHASM task implementations","Keep task struct definitions in sync with persisted component data","Guard type assertions with the comma-ok form","Test tasks against malformed/legacy payloads"],"tags":["chasm","panic","side-effect-task","repanic","deserialization"],"backgroundTag":"panic-in-chasm-task","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}