gastownhall/beads · error

get all dependency records from %s: %w

Error message

get all dependency records from %s: %w

What it means

getAllDependencyRecordsIntoFromTable wraps the error from tx.QueryContext when loading every dependency record from a given table (issues_dependencies or wisp_dependencies, chosen by depTable). The message includes the table name and the underlying driver error via %w, so callers can tell which table's full scan failed and why. GetAllDependencyRecordsInTx fans out to this for each dependency table.

Source

Thrown at internal/storage/issueops/dependency_queries.go:41

			return nil, err
		}
	}
	return result, nil
}

//nolint:gosec // G201: depTable is "dependencies" or "wisp_dependencies" (hardcoded by caller).
func getAllDependencyRecordsIntoFromTable(ctx context.Context, tx DBTX, depTable string, result map[string][]*types.Dependency) error {
	// Total order: issue_id alone is only a grouping key; without a tiebreaker the
	// intra-issue dependency slice is plan-dependent (export churn, unstable --json).
	// Mirrors labels bulk-load (issue_id, label). The separate typed-target unique
	// keys don't make (issue_id, depends_on_id, type) total, so `id` closes it.
	rows, err := tx.QueryContext(ctx, fmt.Sprintf(`
			SELECT issue_id, %s AS depends_on_id, type, created_at, created_by, metadata, thread_id
			FROM %s
			ORDER BY issue_id, depends_on_id, type, id
		`, DepTargetExpr, depTable))
	if err != nil {
		return fmt.Errorf("get all dependency records from %s: %w", depTable, err)
	}
	defer rows.Close()

	for rows.Next() {
		dep, scanErr := scanDependencyRow(rows)
		if scanErr != nil {
			return fmt.Errorf("get all dependency records from %s: %w", depTable, scanErr)
		}
		result[dep.IssueID] = append(result[dep.IssueID], dep)
	}
	if err := rows.Err(); err != nil {
		return fmt.Errorf("get all dependency records from %s: %w", depTable, err)
	}
	return nil
}

// GetDependencyRecordsForIssuesInTx returns dependency records for specific issues,
// routing each ID to dependencies or wisp_dependencies based on wisp status.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the %w cause with errors.As to identify the driver error (connection, syntax, privilege) and fix that root cause.
  2. Retry the containing transaction; the query is read-only within it so a fresh transaction is safe.
  3. After a version upgrade, verify the schema has the expected dependency tables and columns (the driver owns schema; do not patch around it).
  4. Check the database user's SELECT grants on both dependency tables.
Defensive patterns

Strategy: retry

Try / catch

deps, err := GetAllDependencyRecordsInTx(ctx, tx)
if err != nil {
    var drv driver.Error
    if errors.As(err, &drv) {
        // inspect wrapped driver error (connection/privilege/syntax)
    }
    return fmt.Errorf("load dependencies: %w", err)
}

Prevention

When it happens

Trigger: tx.QueryContext failing inside GetAllDependencyRecordsInTx — e.g. connection loss mid-transaction, an SQL syntax/permission problem from the interpolated DepTargetExpr/depTable, or a driver error while issuing the SELECT over all dependency rows.

Common situations: Server restarted or connection dropped during a long export/sync; schema mismatch after a version upgrade where the expected dependency table or columns are missing; running against a database user lacking SELECT privileges.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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