{"record":{"id":"66221abeff2a3827","repo":"AdguardTeam/AdGuardHome","slug":"panic-recovered-value-of-type-1-t-1-v","errorCode":null,"errorMessage":"panic: recovered value of type %[1]T: %[1]v","messagePattern":"panic: recovered value of type %\\[1\\]T: %\\[1\\]v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/stats/stats.go","lineNumber":229,"sourceCode":"\ts.logger.Debug(\"initialized\")\n\n\treturn s, nil\n}\n\n// withRecovered turns the value recovered from panic if any into an error and\n// combines it with the one pointed by orig.  orig must be non-nil.\nfunc withRecovered(orig *error) {\n\tp := recover()\n\tif p == nil {\n\t\treturn\n\t}\n\n\tvar err error\n\tswitch p := p.(type) {\n\tcase error:\n\t\terr = fmt.Errorf(\"panic: %w\", p)\n\tdefault:\n\t\terr = fmt.Errorf(\"panic: recovered value of type %[1]T: %[1]v\", p)\n\t}\n\n\t*orig = errors.WithDeferred(*orig, err)\n}\n\n// type check\nvar _ Interface = (*StatsCtx)(nil)\n\n// Start implements the [Interface] interface for *StatsCtx.\nfunc (s *StatsCtx) Start() {\n\ts.initWeb()\n\n\tgo s.periodicFlush()\n}\n\n// Close implements the [io.Closer] interface for *StatsCtx.\nfunc (s *StatsCtx) Close() (err error) {\n\tdb := s.db.Swap(nil)","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/stats/stats.go#L211-L247","documentation":"withRecovered converts a recovered panic whose value is NOT an error into this formatted error, including the value's type and representation. It is deferred-wrapped onto stats.New's returned error.","triggerScenarios":"A panic inside stats.New with a non-error value, e.g. panic(\"string\"), panic(int), runtime errors surfaced as non-error values, or nil-map writes that recover as runtime.Error (which is an error) vs custom string panics.","commonSituations":"Third-party code panicking with strings/structs; internal invariant violations during stats initialization.","solutions":["Read the type and value in the message to locate the panic origin","Reproduce with a debugger or with the deferred recover removed to get the stack","Check inputs to stats.New for nil/invalid fields"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"caught %T %v\", r, r) } }()","preventionTips":["Never panic with non-error values in shared code paths","Log recovered panics with stack traces"],"tags":["stats","panic","recovery"],"backgroundTag":"recovered-panic","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}