{"record":{"id":"c1fbb462f8586fe6","repo":"gastownhall/beads","slug":"iterate-dependency-targets-w","errorCode":null,"errorMessage":"iterate dependency targets: %w","messagePattern":"iterate dependency targets: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":745,"sourceCode":"\t\t}\n\t\tswitch column {\n\t\tcase \"depends_on_issue_id\":\n\t\t\trow.issueTarget = sql.NullString{String: newID, Valid: true}\n\t\t\trow.wispTarget = sql.NullString{}\n\t\t\trow.external = sql.NullString{}\n\t\tcase \"depends_on_wisp_id\":\n\t\t\trow.issueTarget = sql.NullString{}\n\t\t\trow.wispTarget = sql.NullString{String: newID, Valid: true}\n\t\t\trow.external = sql.NullString{}\n\t\tdefault:\n\t\t\t_ = queryRows.Close()\n\t\t\treturn fmt.Errorf(\"replace dependency target: unsupported typed column %q\", column)\n\t\t}\n\t\trows = append(rows, row)\n\t}\n\t_ = queryRows.Close()\n\tif err := queryRows.Err(); err != nil {\n\t\treturn fmt.Errorf(\"iterate dependency targets: %w\", err)\n\t}\n\n\t//nolint:gosec // table and column are hardcoded by callers.\n\tif _, err := tx.ExecContext(ctx, fmt.Sprintf(`DELETE FROM %s WHERE %s = ? OR (%s = ? AND depends_on_external IS NULL)`, table, column, DepTargetExpr), oldID, oldID); err != nil {\n\t\treturn fmt.Errorf(\"delete old dependency target: %w\", err)\n\t}\n\tfor _, row := range rows {\n\t\t// The retargeted edge's natural key is (issue_id, newID): the switch above\n\t\t// set exactly one typed target column to newID. Re-derive id from it so the\n\t\t// rewritten row stays merge-safe and keeps a clone-stable primary key (#4259).\n\t\t//nolint:gosec // table is hardcoded by callers.\n\t\tif _, err := tx.ExecContext(ctx, fmt.Sprintf(`\n\t\t\tINSERT INTO %s (id, issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external, type, created_at, created_by, metadata, thread_id)\n\t\t\tVALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n\t\t`, table), depid.New(row.issueID, newID), row.issueID, nullStringValue(row.issueTarget), nullStringValue(row.wispTarget), nullStringValue(row.external), row.depType, nullTimeValue(row.createdAt), nullStringValue(row.createdBy), nullStringValue(row.metadata), nullStringValue(row.threadID)); err != nil {\n\t\t\treturn fmt.Errorf(\"insert replacement dependency target: %w\", err)\n\t\t}\n\t}","sourceCodeStart":727,"sourceCodeEnd":763,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L727-L763","documentation":"This error wraps rows.Err() after iterating the dependency-target result set in replaceDependencyTargetInTx. It reports streaming errors that occur mid-iteration (connection loss, killed query, replication error), as opposed to the initial query or per-row scan failures.","triggerScenarios":"UpdateIssueIDInTx / UpdateWispIDInTx rename, while streaming rows matching the old target ID from dependencies or wisp_dependencies: the result stream errors after partial reads.","commonSituations":"Large edge fan-in/out to a single renamed issue causing a slow scan that hits a timeout; network interruption to the Dolt/MySQL server; server shutdown mid-query.","solutions":["Read the wrapped driver error for the underlying cause","Retry the rename; the transaction ensures no partial delete/reinsert state persists","Raise query timeouts or batch the rename into smaller groups of issues","Check server logs for aborted queries at the failure time"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Preflight: connection health and expected row count\nif err := db.PingContext(ctx); err != nil { return err }\nvar n int\ndb.Get(&n, `SELECT COUNT(*) FROM dependencies WHERE depends_on_issue_id = ? OR depends_on_wisp_id = ?`, oldID, oldID)\nlog.Printf(\"retargeting %d dependency rows\", n)","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    err := renameWithDeps(tx, oldID, newID)\n    if err == nil { break }\n    if !isTransient(err) { return err }\n    time.Sleep(backoff(attempt)) // whole tx rolled back; retry is safe\n}","preventionTips":["Increase driver readTimeout for renames touching many edges","Retry complete operations only — the delete/reinsert pair is atomic per transaction","Avoid renames during replica failover windows","Split very large renames into batches of issues"],"tags":["database","sql","rows-iteration","connection"],"backgroundTag":"sql-rows-iteration-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}