{"record":{"id":"336ad85e114fcdda","repo":"vxcontrol/pentagi","slug":"failed-to-update-tool-call-log-result-w","errorCode":null,"errorMessage":"failed to update tool call log result: %w","messagePattern":"failed to update tool call log result: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/tclog.go","lineNumber":88,"sourceCode":"\n\tw.pub.ToolCallLogAdded(ctx, tc)\n\n\treturn tc.ID, nil\n}\n\nfunc (w *flowToolCallLogWorker) UpdateLogSuccess(\n\tctx context.Context,\n\tid int64,\n\tresult string,\n\tdurationSeconds float64,\n) error {\n\ttc, err := w.db.UpdateToolcallFinishedResult(ctx, database.UpdateToolcallFinishedResultParams{\n\t\tResult:          result,\n\t\tDurationSeconds: durationSeconds,\n\t\tID:              id,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update tool call log result: %w\", err)\n\t}\n\n\tw.pub.ToolCallLogUpdated(ctx, tc)\n\n\treturn nil\n}\n\nfunc (w *flowToolCallLogWorker) UpdateLogFailed(\n\tctx context.Context,\n\tid int64,\n\tresult string,\n\tdurationSeconds float64,\n) error {\n\ttc, err := w.db.UpdateToolcallFailedResult(ctx, database.UpdateToolcallFailedResultParams{\n\t\tResult:          result,\n\t\tDurationSeconds: durationSeconds,\n\t\tID:              id,\n\t})","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/tclog.go#L70-L106","documentation":"UpdateLogSuccess marks a tool call as finished by calling db.UpdateToolcallFinishedResult. This error wraps the underlying SQL failure — most commonly sql.ErrNoRows because the toolcall ID does not exist (or belongs to another flow / was already finished, depending on the query), or a transient DB error.","triggerScenarios":"Calling UpdateLogSuccess with an id that was never inserted, an id from a different flow worker, a duplicate completion after the row was already transitioned out of running status, or DB connection loss/canceled context during the UPDATE.","commonSituations":"Double completion when both success and failure paths fire for one call; using an ID cached from a previous flow run; DB failover mid-execution of long-running tools.","solutions":["Check errors.Is(err, sql.ErrNoRows) — if so the ID is wrong or the row was deleted","Log and return the ID from PutLog rather than reconstructing or caching it","Guard against double-update with a status check / idempotency in the calling agent code","Inspect the wrapped error for constraint or connection details in the DB logs","Retry only transient driver errors; missing rows will never succeed on retry"],"exampleFix":"// before\nif err := worker.UpdateLogSuccess(ctx, id, result, dur); err != nil {\n    return fmt.Errorf(\"mark success: %w\", err)\n}\n// after\nif err := worker.UpdateLogSuccess(ctx, id, result, dur); err != nil {\n    if errors.Is(err, sql.ErrNoRows) {\n        log.Warn().Int64(\"toolcall_id\", id).Msg(\"toolcall already gone, skipping success update\")\n        return nil\n    }\n    return fmt.Errorf(\"mark success: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"func toolcallExists(ctx context.Context, q database.Querier, id int64) bool {\n    _, err := q.GetFlowToolcall(ctx, database.GetFlowToolcallParams{ID: id, FlowID: currentFlowID})\n    return err == nil\n}","typeGuard":"func isNoRows(err error) bool { return errors.Is(err, sql.ErrNoRows) }","tryCatchPattern":"err := worker.UpdateLogSuccess(ctx, id, result, dur)\nswitch {\ncase err == nil:\n    // ok\ncase isNoRows(err):\n    log.Warn().Int64(\"id\", id).Msg(\"toolcall missing; skipping success update\")\ncase errors.Is(err, context.Canceled):\n    // treat as non-fatal, result already delivered to agent\n    log.Warn().Err(err).Msg(\"success update canceled\")\ndefault:\n    return fmt.Errorf(\"update success: %w\", err)\n}","preventionTips":["Complete each toolcall exactly once — use a state machine around PutLog/Update*","Never cache toolcall IDs across flow restarts","Log the returned tc.ID from PutLog immediately and pass it explicitly","Treat sql.ErrNoRows as idempotent-success in idempotent update paths","Watch DB failover logs during long tool executions"],"tags":["database","postgresql","no-rows"],"backgroundTag":"sql-no-rows","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}