{"record":{"id":"9a0d2250042ffcc1","repo":"vxcontrol/pentagi","slug":"failed-to-ensure-chain-consistency-for-subtask-d","errorCode":null,"errorMessage":"failed to ensure chain consistency for subtask %d: %w","messagePattern":"failed to ensure chain consistency for subtask (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/subtask.go","lineNumber":316,"sourceCode":"\n\tif stw.IsWaiting() {\n\t\treturn fmt.Errorf(\"subtask is waiting, put input first\")\n\t}\n\n\tif err := stw.SetStatus(ctx, database.SubtaskStatusRunning); err != nil {\n\t\tstw.handleInterrupting(err)\n\t\treturn err\n\t}\n\n\tvar (\n\t\ttaskID     = stw.subtaskCtx.TaskID\n\t\tsubtaskID  = stw.subtaskCtx.SubtaskID\n\t\tmsgChainID = stw.subtaskCtx.MsgChainID\n\t)\n\n\tif err := stw.subtaskCtx.Provider.EnsureChainConsistency(ctx, msgChainID); err != nil {\n\t\tstw.handleInterrupting(err)\n\t\treturn fmt.Errorf(\"failed to ensure chain consistency for subtask %d: %w\", subtaskID, err)\n\t}\n\n\tperformResult, err := stw.subtaskCtx.Provider.PerformAgentChain(ctx, taskID, subtaskID, msgChainID)\n\tif err != nil {\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\tctx = context.Background()\n\t\t}\n\t\terrChainConsistency := stw.subtaskCtx.Provider.EnsureChainConsistency(ctx, msgChainID)\n\t\tif errChainConsistency != nil {\n\t\t\terr = errors.Join(err, errChainConsistency)\n\t\t}\n\t\t_ = stw.SetStatus(ctx, database.SubtaskStatusWaiting)\n\t\treturn fmt.Errorf(\"failed to perform agent chain for subtask %d: %w\", subtaskID, err)\n\t}\n\n\tswitch performResult {\n\tcase providers.PerformResultWaiting:\n\t\tif err := stw.SetStatus(ctx, database.SubtaskStatusWaiting); err != nil {","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/subtask.go#L298-L334","documentation":"Before executing the agent chain, Run calls Provider.EnsureChainConsistency to repair/validate the LLM message chain (e.g. dangling tool calls after a crash). If that fails, the error is wrapped as 'failed to ensure chain consistency for subtask %d' and the subtask is reset to Waiting via handleInterrupting when the cause is a context interruption.","triggerScenarios":"EnsureChainConsistency fails on DB errors while reading/repairing the chain rows, a cancelled/deadline-exceeded ctx, or a corrupted/incomplete chain (e.g. assistant message with a dangling tool_call after a previous crash) that the repair logic cannot fix.","commonSituations":"Previous Run crashed mid-chain (container killed, OOM, pod restart) leaving a broken chain; database outage at chain-repair time; flow data restored from backup with partially written msgchain rows.","solutions":["Read the wrapped error: for context.Canceled/DeadlineExceeded retry with a fresh context (handleInterrupting already reset the subtask to Waiting, so just call Run again).","For corrupted chains, delete/reset the msgchain rows for this subtask (or recreate the subtask) so EnsureChainConsistency can rebuild cleanly.","Verify DB health and migrations — chain repair reads and writes msgchain tables and fails on connectivity or missing tables.","Check provider logs for which chain message was inconsistent; manually truncate trailing dangling tool calls if the automatic repair refuses."],"exampleFix":"// before\nif err := worker.Run(ctx); err != nil {\n\treturn err\n}\n// after\nif err := worker.Run(ctx); err != nil {\n\tif errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n\t\tresetCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\t\tdefer cancel()\n\t\treturn worker.Run(resetCtx) // subtask was reset to Waiting by handleInterrupting\n\t}\n\treturn err\n}","handlingStrategy":"retry","validationCode":"// pre-check that the subtask is readable before resuming\nif _, err := worker.GetStatus(ctx); err != nil {\n\treturn err // cannot even read subtask; DB issue\n}","typeGuard":"func isInterruptErr(err error) bool {\n\treturn errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"if err := worker.Run(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"failed to ensure chain consistency\") {\n\t\tif isInterruptErr(err) {\n\t\t\t// subtask already reset to Waiting; retry with fresh ctx\n\t\t\tresetCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\t\t\tdefer cancel()\n\t\t\treturn worker.Run(resetCtx)\n\t\t}\n\t\t// corrupted chain: recreate the subtask/chain\n\t}\n\treturn err\n}","preventionTips":["Gracefully shut down workers (cancel + drain) so chains never end mid tool-call.","Run migrations and keep the msgchain store healthy.","On unrecoverable corruption, recreate the subtask rather than retrying Run forever.","Retry interrupted runs with a fresh background context and timeout."],"tags":["go","provider","message-chain","consistency"],"backgroundTag":"chain-consistency-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}