{"record":{"id":"eb88c8c37eb9996c","repo":"gastownhall/beads","slug":"stale-issues-rows-w","errorCode":null,"errorMessage":"stale issues rows: %w","messagePattern":"stale issues rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/stale.go","lineNumber":83,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get stale issues: %w\", err)\n\t}\n\n\t// Collect IDs first, then batch-fetch full issues.\n\t// Close rows explicitly before the nested fetch — MySQL/Dolt drivers\n\t// can't handle multiple active result sets on one connection.\n\tvar ids []string\n\tfor rows.Next() {\n\t\tvar id string\n\t\tif err := rows.Scan(&id); err != nil {\n\t\t\trows.Close()\n\t\t\treturn nil, fmt.Errorf(\"failed to scan stale issue id: %w\", err)\n\t\t}\n\t\tids = append(ids, id)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\trows.Close()\n\t\treturn nil, fmt.Errorf(\"stale issues rows: %w\", err)\n\t}\n\trows.Close()\n\n\tif len(ids) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// GetIssuesByIDsInTx returns issues in arbitrary order (WHERE IN),\n\t// so re-order to preserve the updated_at ASC ordering from the query.\n\tissues, err := GetIssuesByIDsInTx(ctx, tx, ids, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tissueByID := make(map[string]*types.Issue, len(issues))\n\tfor _, iss := range issues {\n\t\tif iss != nil {\n\t\t\tissueByID[iss.ID] = iss","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/stale.go#L65-L101","documentation":"After iterating rows, GetStaleIssuesInTx calls rows.Err() to detect failures that occurred during row iteration and wraps it with 'stale issues rows: %w'. This means the connection dropped or the query was aborted partway through streaming the stale issue ids — not a query-preparation or scan problem.","triggerScenarios":"Network interruption to the Dolt/MySQL server while rows are being streamed; server-side query kill or timeout during iteration; context cancellation while rows.Next() is advancing; connection closed by the pool mid-iteration.","commonSituations":"Long stale scans over big issues tables hitting an idle-connection timeout; flaky network to a remote Dolt server; server restarts during a sweep/stale job; proxy/load-balancer idle timeouts.","solutions":["Read the wrapped driver error to distinguish connection-lost vs context cancelled.","Retry the whole operation with a fresh transaction and connection — iteration errors are typically transient.","Increase client/server idle and read timeouts if scans of large tables routinely exceed them.","Keep the ctx deadline generous enough for the row count expected, and avoid sharing the tx across goroutines."],"exampleFix":"// before\nissues, err := GetStaleIssuesInTx(ctx, tx, filter) // dies mid-iteration on slow network\n// after\nfor attempt := 0; attempt < 3; attempt++ {\n    issues, err = GetStaleIssuesInTx(ctx, tx, filter)\n    if err == nil { break }\n    time.Sleep(time.Second * time.Duration(attempt+1))\n}","handlingStrategy":"retry","validationCode":"// ensure the connection is healthy before a long streaming scan\nif err := tx.PingContext(ctx); err != nil { return fmt.Errorf(\"connection unhealthy: %w\", err) }","typeGuard":null,"tryCatchPattern":"issues, err := issueops.GetStaleIssuesInTx(ctx, tx, filter)\nif err != nil && strings.Contains(err.Error(), \"stale issues rows:\") {\n    // transient iteration failure: reopen tx and retry with backoff\n}","preventionTips":["Set generous idle/read timeouts on the Dolt/MySQL connection","Avoid sweeping huge tables over flaky networks; run locally or batch","Don't share a tx across goroutines during iteration","Give the ctx enough budget for the expected row count"],"tags":["go","sql","network","row-iteration"],"backgroundTag":"connection-lost-mid-query","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}