gastownhall/beads · error

iterate dependency targets: %w

Error message

iterate dependency targets: %w

What it means

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.

Source

Thrown at internal/storage/issueops/dependencies.go:745

		}
		switch column {
		case "depends_on_issue_id":
			row.issueTarget = sql.NullString{String: newID, Valid: true}
			row.wispTarget = sql.NullString{}
			row.external = sql.NullString{}
		case "depends_on_wisp_id":
			row.issueTarget = sql.NullString{}
			row.wispTarget = sql.NullString{String: newID, Valid: true}
			row.external = sql.NullString{}
		default:
			_ = queryRows.Close()
			return fmt.Errorf("replace dependency target: unsupported typed column %q", column)
		}
		rows = append(rows, row)
	}
	_ = queryRows.Close()
	if err := queryRows.Err(); err != nil {
		return fmt.Errorf("iterate dependency targets: %w", err)
	}

	//nolint:gosec // table and column are hardcoded by callers.
	if _, 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 {
		return fmt.Errorf("delete old dependency target: %w", err)
	}
	for _, row := range rows {
		// The retargeted edge's natural key is (issue_id, newID): the switch above
		// set exactly one typed target column to newID. Re-derive id from it so the
		// rewritten row stays merge-safe and keeps a clone-stable primary key (#4259).
		//nolint:gosec // table is hardcoded by callers.
		if _, err := tx.ExecContext(ctx, fmt.Sprintf(`
			INSERT INTO %s (id, issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external, type, created_at, created_by, metadata, thread_id)
			VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
		`, 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 {
			return fmt.Errorf("insert replacement dependency target: %w", err)
		}
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error for the underlying cause
  2. Retry the rename; the transaction ensures no partial delete/reinsert state persists
  3. Raise query timeouts or batch the rename into smaller groups of issues
  4. Check server logs for aborted queries at the failure time
Defensive patterns

Strategy: retry

Validate before calling

// Preflight: connection health and expected row count
if err := db.PingContext(ctx); err != nil { return err }
var n int
db.Get(&n, `SELECT COUNT(*) FROM dependencies WHERE depends_on_issue_id = ? OR depends_on_wisp_id = ?`, oldID, oldID)
log.Printf("retargeting %d dependency rows", n)

Try / catch

for attempt := 0; attempt < 3; attempt++ {
    err := renameWithDeps(tx, oldID, newID)
    if err == nil { break }
    if !isTransient(err) { return err }
    time.Sleep(backoff(attempt)) // whole tx rolled back; retry is safe
}

Prevention

When it happens

Trigger: UpdateIssueIDInTx / UpdateWispIDInTx rename, while streaming rows matching the old target ID from dependencies or wisp_dependencies: the result stream errors after partial reads.

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/c1fbb462f8586fe6. Report an issue: GitHub.