{"record":{"id":"15e42bfb15db9391","repo":"flipped-aurora/gin-vue-admin","slug":"panic-v","errorCode":null,"errorMessage":"panic: %v","messagePattern":"panic: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_timed_task_runner.go","lineNumber":109,"sourceCode":"\t\ts.alertFailure(t, errMsg)\n\t}\n}\n\n// runMethod 执行已注册本体方法。\n// 超时语义: 只能标记状态, goroutine 无法强杀; 任务函数应响应 ctx 取消。\nfunc (s *TimedTaskService) runMethod(t system.SysTimedTask) (string, error) {\n\tfn, ok := task.Get(t.MethodName)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"方法 %s 未注册(需在 initialize/timer.go 经 task.Register 注册)\", t.MethodName)\n\t}\n\tctx, cancel := context.WithTimeout(datascope.WithSystem(context.Background()), defaultMethodTimeout)\n\tdefer cancel()\n\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tdone <- fmt.Errorf(\"panic: %v\", r)\n\t\t\t}\n\t\t}()\n\t\tdone <- fn(ctx, json.RawMessage(t.Params))\n\t}()\n\tselect {\n\tcase err := <-done:\n\t\tif err != nil && errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn \"\", errTaskTimeout\n\t\t}\n\t\treturn \"\", err\n\tcase <-ctx.Done():\n\t\treturn \"\", errTaskTimeout\n\t}\n}\n\n// runHTTP 执行 HTTP 回调(SSRF 防护见 sys_timed_task_http.go)\nfunc (s *TimedTaskService) runHTTP(t system.SysTimedTask) (string, error) {\n\tu, err := url.Parse(t.HttpUrl)","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_timed_task_runner.go#L91-L127","documentation":"runMethod runs the task function in a goroutine and recovers panics, converting them into an error \"panic: %v\" delivered over the done channel. The timed task itself panicked; the runner can't strongly kill goroutines, so this is the post-hoc report of the crash.","triggerScenarios":"The registered task function (or anything it calls) panics — nil pointer dereference, index out of range, panic() called explicitly — while executing with the task's ctx and JSON params.","commonSituations":"Task function assumes config/DB initialized but runs in an environment where they're nil; malformed JSON params cause a downstream panic; bug in task code triggered only with certain parameter values.","solutions":["Read the %v payload in the error to identify the panic site and fix the underlying bug in the task function","Add defensive checks in the task function for nil dependencies and malformed params before use","Unmarshal t.Params safely inside the task (json.RawMessage) and validate fields before use"],"exampleFix":"// before\nvar cfg map[string]string\njson.Unmarshal(params, &cfg)\nurl := cfg[\"url\"] // may panic if params nil\n// after\nvar cfg map[string]string\nif err := json.Unmarshal(params, &cfg); err != nil { return err }\nurl, ok := cfg[\"url\"]; if !ok { return errors.New(\"missing url\") }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := RunTask(t)\nif err != nil {\n    var pe *PanicLikeError\n    if strings.HasPrefix(err.Error(), \"panic: \") {\n        log.Errorf(\"timed task %s panicked: %v\", t.MethodName, err)\n    }\n}","preventionTips":["Keep task functions small and nil-check all inputs (params, config, globals)","Validate/unmarshal t.Params defensively at the top of each task function","Write unit tests for each registered task function covering empty/invalid params"],"tags":["panic","timed-task","go","goroutine"],"backgroundTag":"recovered-panic-in-goroutine","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}