multica-ai/multica · error
update Codex task_usage batch: %w
Error message
update Codex task_usage batch: %w
What it means
Returned when one UPDATE batch of the correction loop fails during the --execute phase. The query recomputes eligible rows per batch (same predicate as the dry-run), sets input_tokens = GREATEST(input_tokens - cache_read_tokens, 0), and returns counts. Because each batch commits independently and the predicate excludes already-corrected rows, earlier batches stay applied; re-running resumes rather than double-applying.
Source
Thrown at server/cmd/backfill_codex_usage_cache/main.go:292
ORDER BY COALESCE(tu.updated_at, tu.created_at), tu.id
LIMIT $3
FOR UPDATE OF tu SKIP LOCKED
),
updated AS (
UPDATE task_usage tu
SET input_tokens = GREATEST(tu.input_tokens - tu.cache_read_tokens, 0),
updated_at = now()
FROM candidates c
WHERE tu.id = c.id
RETURNING c.removed_tokens
)
SELECT COUNT(*)::bigint, COALESCE(SUM(removed_tokens), 0)::bigint FROM updated`
var totalRows, totalRemoved int64
for {
var rows, removed int64
if err := pool.QueryRow(ctx, query, cfg.cutoff, cfg.workspaceID, cfg.batchSize).Scan(&rows, &removed); err != nil {
return totalRows, totalRemoved, fmt.Errorf("update Codex task_usage batch: %w", err)
}
if rows == 0 {
break
}
totalRows += rows
totalRemoved += removed
slog.Info("updated Codex task_usage batch", "rows", rows, "input_tokens_removed", removed, "total_rows", totalRows)
if cfg.sleepBetweenBatches > 0 {
select {
case <-time.After(cfg.sleepBetweenBatches):
case <-ctx.Done():
return totalRows, totalRemoved, ctx.Err()
}
}
}
return totalRows, totalRemoved, nil
}
View on GitHub (pinned to 2c0912b6ec)
Solutions
- Re-run the tool with the same --cutoff — completed batches no longer match the eligibility predicate, so it resumes from where it stopped.
- Address the wrapped cause: raise statement/lock timeouts for the session, or run during lower write traffic.
- Use --sleep-between-batches to reduce contention if lock conflicts recur.
Example fix
# before ./backfill_codex_usage_cache --cutoff ... --execute # update Codex task_usage batch: ... lock timeout # after: idempotent resume, gentler pacing ./backfill_codex_usage_cache --cutoff 2026-06-01T12:00:00Z --execute --sleep-between-batches 500ms
Defensive patterns
Strategy: retry
Prevention
- Re-run with the same --cutoff after any mid-batch failure — corrected rows self-exclude, so it resumes.
- Use --sleep-between-batches on busy production tables to avoid lock conflicts.
- Run during low write traffic or with relaxed lock_timeout for the session.
When it happens
Trigger: A dead connection, statement timeout, or lock conflict on task_usage mid-loop; ctx cancelled (SIGINT) during the update; a concurrent writer altering rows the UPDATE targets.
Common situations: Long backfills on busy production tables hitting lock_timeout/statement_timeout; postgres failover mid-run; operators interrupting the --execute phase.
Related errors
- iterate dry-run summary: %w
- read database clock: %w
- connect to database: %w
- ping database: %w
- acquire advisory-lock connection: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/ff422e6861611d40.
Report an issue: GitHub.