gastownhall/beads · error
journal: iterate dependency removals from %s: %w
Error message
journal: iterate dependency removals from %s: %w
What it means
This error wraps a rows.Err() failure encountered while iterating the result set of dependency-removal rows read from a journal table inside dependencyEdgesInTableForIssueIDsInTx. The library throws it because a streaming row iteration can fail mid-scan (connection drop, driver decode error), and such failures must abort the rebuild of dependency edges rather than silently return a partial set. The wrapped table name identifies which journal table ('dependencies' or wisp variant) the iteration failed on.
Source
Thrown at internal/storage/issueops/journal_dependencies.go:105
WHERE issue_id IN (%s) OR %s IN (%s)
`, DepTargetExpr, table, inClause, DepTargetExpr, inClause), queryArgs...)
if err != nil {
if optionalBlockedTable(table) && isTableNotExistError(err) {
continue
}
return nil, fmt.Errorf("journal: query dependency removals from %s: %w", table, err)
}
for rows.Next() {
var edge journalDependencyEdge
if err := rows.Scan(&edge.source, &edge.target, &edge.kind, &edge.metadata); err != nil {
_ = rows.Close()
return nil, fmt.Errorf("journal: scan dependency removal from %s: %w", table, err)
}
byKey[dependencyEdgeKey(edge)] = edge
}
if err := rows.Err(); err != nil {
_ = rows.Close()
return nil, fmt.Errorf("journal: iterate dependency removals from %s: %w", table, err)
}
if err := rows.Close(); err != nil {
return nil, fmt.Errorf("journal: close dependency removals from %s: %w", table, err)
}
}
return sortedDependencyEdges(byKey), nil
}
func dependencyEdgeKey(edge journalDependencyEdge) string {
return edge.source + "\x00" + edge.target + "\x00" + edge.kind + "\x00" + edge.metadata
}
func sortedDependencyEdges(byKey map[string]journalDependencyEdge) []journalDependencyEdge {
edges := make([]journalDependencyEdge, 0, len(byKey))
for _, edge := range byKey {
edges = append(edges, edge)
}
sort.Slice(edges, func(i, j int) bool {View on GitHub (pinned to 71377f2769)
Solutions
- Check database connectivity and retry the operation once the connection is healthy
- Increase the context timeout for the transaction so iteration is not cut off
- Inspect the wrapped error (%w chain) for driver-specific causes (driver.ErrBadConn, context.DeadlineExceeded)
- Reduce batch size of issue IDs to shrink result sets on slow remote backends
Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return fmt.Errorf("context already done before dependency rebuild: %w", err) } Try / catch
edges, err := dependencyEdgesForIssueIDsInTx(ctx, tx, ids)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded) {
// transient: retry with fresh connection/backoff
}
return err
} Prevention
- Keep transactions short to reduce mid-iteration connection loss
- Set generous but bounded context deadlines for bulk journal reads
- Monitor driver.ErrBadConn rates and pool health
- Batch issue IDs to keep result sets small on remote backends
When it happens
Trigger: Calling RecordDependencyRemovalsForTableInTx or dependencyEdgesForIssueIDsInTx, which invoke dependencyEdgesInTableForIssueIDsInTx, when the underlying rows iterator returns a non-nil error after rows.Next() exhausts — e.g. the Dolt/MySQL connection breaks mid-result or the context deadline expires during iteration.
Common situations: Remote Dolt backends dropping connections on large result sets; context cancellation/timeouts during long transactions (GH#3414-style round-trip latency); server restarts mid-query.
Related errors
- capture dependency edges for rename %s -> %s: %w
- journal: query dependency removals from %s: %w
- journal: scan dependency removal from %s: %w
- journal: close dependency removals from %s: %w
- loading deps for %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/65348a215156cf29.
Report an issue: GitHub.