{"record":{"id":"b5e7afc274fb0c87","repo":"temporalio/temporal","slug":"panic-e","errorCode":null,"errorMessage":"panic(e)","messagePattern":"panic\\(e\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/executable.go","lineNumber":969,"sourceCode":"\tif err != nil {\n\t\tmetrics.CircuitBreakerExecutableBlocked.With(e.metricsHandler).Record(1)\n\t\t// Return a resource exhausted error to ensure that this task is retried less aggressively\n\t\t// and does not go to the DLQ.\n\t\treturn fmt.Errorf(\n\t\t\t\"%w: %w\",\n\t\t\tserviceerror.NewResourceExhausted(\n\t\t\t\tenumspb.RESOURCE_EXHAUSTED_CAUSE_CIRCUIT_BREAKER_OPEN,\n\t\t\t\t\"circuit breaker rejection\",\n\t\t\t),\n\t\t\terr,\n\t\t)\n\t}\n\n\tdefer func() {\n\t\te := recover()\n\t\tif e != nil {\n\t\t\tdoneCb(false)\n\t\t\tpanic(e)\n\t\t}\n\t}()\n\n\terr = e.Executable.Execute()\n\tvar destinationDownErr *queueserrors.DestinationDownError\n\tif errors.As(err, &destinationDownErr) {\n\t\terr = destinationDownErr.Unwrap()\n\t}\n\n\tdoneCb(destinationDownErr == nil)\n\treturn err\n}\n","sourceCodeStart":951,"sourceCodeEnd":982,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/executable.go#L951-L982","documentation":"This deferred recover/re-panic wrapper around Executable.Execute ensures the done callback runs with false when the executable panics, then re-panics to preserve the original crash. The panic(e) is the deliberate re-throw, not a bug; the original panic could be any runtime error inside task execution.","triggerScenarios":"Any panic inside e.Executable.Execute() — nil pointer, index out of range, or a nested panic from task processing — causes the deferred func to invoke doneCb(false) and then re-panic with panic(e).","commonSituations":"Corrupt or unexpected task payloads triggering runtime panics in task processors; bugs in executable task handling code; crashes during rolling upgrades.","solutions":["Inspect the panic stack trace to identify which executable task processor panicked","Fix the underlying nil/error path in the task's Execute implementation","Wrap individual task execution with its own recover if panics from user data are expected","Report to temporal maintainers if a stock task type panics on valid data"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        logger.Error(\"task executable panicked\", \"panic\", r, \"stack\", string(debug.Stack()))\n    }\n}()\nerr = executable.Execute()","preventionTips":["Nil-check all task attributes before Execute","Wrap third-party/untrusted task processing in recover boundaries","Fuzz/validate incoming task payloads","Always invoke completion callbacks via defer so panics cannot skip them"],"tags":["go","panic","recover","task-execution","history-service"],"backgroundTag":"panic-recovery-rethrow","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}