{"record":{"id":"f57bf197121f2ea6","repo":"gastownhall/beads","slug":"wake-expired-defers-iterate-s-w","errorCode":null,"errorMessage":"wake expired defers: iterate %s: %w","messagePattern":"wake expired defers: iterate (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/wake_defers.go","lineNumber":99,"sourceCode":"\t\tSELECT id FROM %s\n\t\tWHERE status = 'deferred' AND defer_until IS NOT NULL\n\t\t  AND defer_until <= UTC_TIMESTAMP()\n\t`, table))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"wake expired defers: scan %s: %w\", table, err)\n\t}\n\tvar expired []string\n\tfor rows.Next() {\n\t\tvar id string\n\t\tif err := rows.Scan(&id); err != nil {\n\t\t\t_ = rows.Close()\n\t\t\treturn nil, fmt.Errorf(\"wake expired defers: scan %s row: %w\", table, err)\n\t\t}\n\t\texpired = append(expired, id)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\t_ = rows.Close()\n\t\treturn nil, fmt.Errorf(\"wake expired defers: iterate %s: %w\", table, err)\n\t}\n\tif err := rows.Close(); err != nil {\n\t\treturn nil, fmt.Errorf(\"wake expired defers: close %s rows: %w\", table, err)\n\t}\n\tif len(expired) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tvar woken []string\n\tnow := time.Now().UTC()\n\tfor _, id := range expired {\n\t\t// row_lock is rewritten so a concurrent claim/update conflicts at\n\t\t// commit time instead of cell-merging with this write — the same\n\t\t// invariant the lease scheme depends on.\n\t\t//nolint:gosec // G201: table is a hardcoded constant from the caller above.\n\t\tres, err := tx.ExecContext(ctx, fmt.Sprintf(`\n\t\t\tUPDATE %s\n\t\t\tSET status = 'open', defer_until = NULL, updated_at = ?, row_lock = ?","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/wake_defers.go#L81-L117","documentation":"Thrown when rows.Err() reports that the result-set iteration itself failed (a mid-stream driver/connection error, not a per-row decode problem). This is distinct from scan errors: the connection dropped or the server aborted the query while streaming ids. The cursor is closed before returning.","triggerScenarios":"Calling WakeExpiredDefersInTx when the MySQL/Dolt connection breaks or the server kills the query partway through streaming the expired-defer id list (timeout, max_allowed_packet issues, server shutdown).","commonSituations":"Long-running wake scans across a flaky network; Dolt server restart during a maintenance pass; wait_timeout expiring on an idle pooled connection.","solutions":["Retry the wake operation once the connection is restored — it is idempotent due to the status re-check in the UPDATE.","Check database server logs for aborted connections or killed queries.","Increase driver timeouts (readTimeout/writeTimeout) if large scans routinely fail.","Verify network stability between beads and the database host."],"exampleFix":"// before: default short driver timeout\ndsn := \"user:pass@tcp(host:3306)/db\"\n// after\ndsn := \"user:pass@tcp(host:3306)/db?timeout=30s&readTimeout=60s&writeTimeout=60s\"","handlingStrategy":"retry","validationCode":"if err := db.PingContext(ctx); err != nil { return fmt.Errorf(\"connection unhealthy before wake: %w\", err) }","typeGuard":null,"tryCatchPattern":"var ids []string\nerr := retry.Do(func() error {\n    var innerErr error\n    ids, innerErr = issueops.WakeExpiredDefersInTx(ctx, tx, tables)\n    return innerErr\n}, retry.OnRetry(func(n uint, e error) { log.Printf(\"wake retry %d: %v\", n, e) }), retry.Attempts(3))","preventionTips":["Set generous readTimeout/writeTimeout in the DSN for long scans.","Keep connections alive; avoid idle timeouts (wait_timeout) during maintenance.","Retry wake operations — the guarded UPDATE makes them idempotent.","Monitor server logs for aborted connections."],"tags":["database","connection-dropped","result-iteration"],"backgroundTag":"connection-reset-during-query","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}