{"record":{"id":"504fb23eca48ebf9","repo":"vxcontrol/pentagi","slug":"task-stop-timeout","errorCode":null,"errorMessage":"task stop timeout","messagePattern":"task stop timeout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/flow.go","lineNumber":844,"sourceCode":"\tctx, span := obs.Observer.NewSpan(ctx, obs.SpanKindInternal, \"controller.flowWorker.Stop\")\n\tdefer span.End()\n\n\tfw.taskMX.Lock()\n\tdefer fw.taskMX.Unlock()\n\n\tfw.taskST()\n\tdone := make(chan struct{})\n\ttimer := time.NewTimer(stopTaskTimeout)\n\tdefer timer.Stop()\n\n\tgo func() {\n\t\tfw.taskWG.Wait()\n\t\tclose(done)\n\t}()\n\n\tselect {\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"task stop timeout\")\n\tcase <-done:\n\t\treturn nil\n\t}\n}\n\nfunc (fw *flowWorker) Rename(ctx context.Context, title string) error {\n\tfw.flowCtx.Provider.SetTitle(title)\n\n\tflow, err := fw.flowCtx.DB.UpdateFlowTitle(ctx, database.UpdateFlowTitleParams{\n\t\tID:    fw.flowCtx.FlowID,\n\t\tTitle: title,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to rename flow %d: %w\", fw.flowCtx.FlowID, err)\n\t}\n\n\tcontainers, err := fw.flowCtx.DB.GetFlowContainers(ctx, fw.flowCtx.FlowID)\n\tif err != nil {","sourceCodeStart":826,"sourceCodeEnd":862,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/flow.go#L826-L862","documentation":"Stop waits for all running tasks (fw.taskWG) to finish behind a pre-configured timeout timer; if taskWG.Wait() hasn't completed when the timer fires, it returns 'task stop timeout' and leaks nothing but leaves the tasks still running/unterminated. It signals that graceful stopping of the flow's tasks exceeded the allowed grace period.","triggerScenarios":"Calling fw.Stop while an assistant task is stuck: a long-running Docker exec command, an LLM streaming call with no deadline, a blocked channel write in the task, or a deadlock in task code — taskWG.Wait() does not return before the timer expires.","commonSituations":"Agent waiting on a hung container command (no timeout configured); LLM provider network stall without ctx deadline; task goroutine blocked publishing to a full channel; very long tool invocation that ignores ctx cancellation.","solutions":["Find which task ignored cancellation: ensure every task/goroutine honors ctx.Done() and uses ctx-scoped Docker/LLM calls.","Increase the stop grace timeout if tasks are legitimately long but cancellable.","Force-kill the flow's Docker containers to unblock stuck exec sessions, then retry Stop.","Add per-tool timeouts so no single tool call can hang a task indefinitely."],"exampleFix":"// before\nout, err := exec.CommandContext(context.Background(), cmd) // ignores stop\n// after\nout, err := exec.CommandContext(ctx, cmd) // aborts when flow stops","handlingStrategy":"try-catch","validationCode":"// ensure no task can outlive the stop grace: every tool/LLM call must take ctx\nfunc tasksCancellable() bool { /* verify exec/LLM calls use fw.ctx-derived contexts */ return true }","typeGuard":"func isStopTimeout(err error) bool {\n    return err != nil && err.Error() == \"task stop timeout\"\n}","tryCatchPattern":"if err := worker.Stop(ctx); err != nil {\n    if isStopTimeout(err) {\n        // escalate: kill flow containers, then mark worker stopped\n        _ = killFlowContainers(ctx, worker.FlowID())\n        return worker.ForceCleanup(ctx)\n    }\n    return err\n}","preventionTips":["Propagate the flow context into every exec, Docker, and LLM call so cancellation reaches tasks.","Set per-tool/per-call timeouts shorter than the stop grace period.","Avoid unbounded channel sends in task goroutines; use select with ctx.Done().","Escalate to forced container cleanup when the graceful window expires."],"tags":["go","timeout","graceful-shutdown","goroutine"],"backgroundTag":"graceful-shutdown-timeout","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}