{"record":{"id":"dab5e3c0f4016588","repo":"hashicorp/nomad","slug":"panic-err-dab5e3","errorCode":null,"errorMessage":"panic(err)","messagePattern":"panic\\(err\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/shared/executor/grpc_server.go","lineNumber":120,"sourceCode":"\treturn &proto.VersionResponse{\n\t\tVersion: v.Version,\n\t}, nil\n}\n\nfunc (s *grpcExecutorServer) Stats(req *proto.StatsRequest, stream proto.Executor_StatsServer) error {\n\tinterval := time.Duration(req.Interval)\n\tif interval == 0 {\n\t\tinterval = time.Second\n\t}\n\n\toutCh, err := s.impl.Stats(stream.Context(), interval)\n\tif err != nil {\n\t\tif rec, ok := err.(structs.Recoverable); ok {\n\t\t\tst := status.New(codes.FailedPrecondition, rec.Error())\n\t\t\tst, err := st.WithDetails(&sproto.RecoverableError{Recoverable: rec.IsRecoverable()})\n\t\t\tif err != nil {\n\t\t\t\t// If this error, it will always error\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\treturn st.Err()\n\t\t}\n\t\treturn err\n\t}\n\n\tfor resp := range outCh {\n\t\tpbStats, err := drivers.TaskStatsToProto(resp)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpresp := &proto.StatsResponse{\n\t\t\tStats: pbStats,\n\t\t}\n\n\t\t// Send the stats\n\t\tif err := stream.Send(presp); err != nil {","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/shared/executor/grpc_server.go#L102-L138","documentation":"When the executor's stats call returns a recoverable error, the gRPC server attaches a RecoverableError detail to a FailedPrecondition status. Building that status should never fail; if st.WithDetails errors, the code panics because the failure indicates a broken proto registration that would persist on every retry.","triggerScenarios":"Returning a structs.Recoverable error from the executor whose status-with-details marshaling fails — practically only when the RecoverableError proto is not registered/linked in the binary.","commonSituations":"Mispackaged or partially built Nomad binary missing the sproto registration; vendoring/build changes that drop the proto import; injecting a custom Recoverable error type into the executor in tests or forks.","solutions":["Ensure the drivers/shared/execsproto package is imported and linked into the build so proto details can marshal","Rebuild the Nomad binary from an unmodified source tree","In forks/tests, make sure custom recoverable errors are serializable into the sproto.RecoverableError detail"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        logger.Error(\"grpc status detail build failed\", \"panic\", r)\n        resp = status.Error(codes.FailedPrecondition, \"recoverable\")\n    }\n}()","preventionTips":["Keep the execsproto package imported so RecoverableError details marshal","Rebuild Nomad from a clean, unmodified source tree","Avoid custom recoverable error types in the executor"],"tags":["grpc","executor","proto","panic"],"backgroundTag":"grpc-status-detail-marshaling-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}