gastownhall/beads · error

get dependency records from %s: %w

Error message

get dependency records from %s: %w

What it means

getDependencyRecordsIntoFromTable wraps the error from tx.QueryContext when fetching dependency records for a specific set of issue IDs from a given table. The per-issue variant used by GetDependencyRecordsForIssuesInTx routes each ID to issues_dependencies or wisp_dependencies; a query failure on either table surfaces here with the table name and driver error via %w.

Source

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

func getDependencyRecordsIntoFromTable(ctx context.Context, tx DBTX, depTable string, ids []string, result map[string][]*types.Dependency) error {
	for start := 0; start < len(ids); start += queryBatchSize {
		end := start + queryBatchSize
		if end > len(ids) {
			end = len(ids)
		}
		batch := ids[start:end]
		placeholders := make([]string, len(batch))
		args := make([]any, len(batch))
		for i, id := range batch {
			placeholders[i] = "?"
			args[i] = id
		}
		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 WHERE issue_id IN (%s) ORDER BY issue_id, depends_on_id, type, id`,
			DepTargetExpr, depTable, strings.Join(placeholders, ",")), args...)
		if err != nil {
			return fmt.Errorf("get dependency records from %s: %w", depTable, err)
		}
		for rows.Next() {
			dep, scanErr := scanDependencyRow(rows)
			if scanErr != nil {
				_ = rows.Close()
				return fmt.Errorf("get dependency records: scan: %w", scanErr)
			}
			result[dep.IssueID] = append(result[dep.IssueID], dep)
		}
		_ = rows.Close()
		if err := rows.Err(); err != nil {
			return fmt.Errorf("get dependency records: rows: %w", err)
		}
	}
	return nil
}

// GetDependentRecordsForIssuesInTx returns raw dependency rows keyed by TARGET

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the %w cause to identify the driver error and address it (connectivity, statement limits).
  2. If the ID list is very large, chunk it into batches (e.g. a few hundred IDs per call) to keep the IN clause within driver limits.
  3. Retry the operation in a fresh transaction; it is a read and safe to repeat.

Example fix

// before: one huge IN clause
records, err := GetDependencyRecordsForIssuesInTx(ctx, tx, allThousandIDs)

// after: batch the IDs
for chunk := range slices.Chunk(allThousandIDs, 500) {
    records, err := GetDependencyRecordsForIssuesInTx(ctx, tx, chunk)
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

const maxBatch = 500
if len(issueIDs) > maxBatch {
    return fmt.Errorf("batch of %d issue IDs exceeds %d; chunk the call", len(issueIDs), maxBatch)
}
for _, id := range issueIDs {
    if id == "" { return fmt.Errorf("empty issue ID in batch") }
}

Try / catch

recs, err := GetDependencyRecordsForIssuesInTx(ctx, tx, ids)
if err != nil {
    var drv driver.Error
    if errors.As(err, &drv) { /* inspect driver cause: statement limits, connection */ }
    return err
}

Prevention

When it happens

Trigger: tx.QueryContext failing in GetDependencyRecordsForIssuesInTx / GetDependencyRecordsForIssuesFromTableInTx — connection loss, driver error building/executing the IN (...) SELECT, or too many placeholders for the driver with a very large ID list.

Common situations: Passing thousands of issue IDs at once producing an oversized IN clause; connection dropped mid-transaction; SQL prepared-statement limits exceeded on some drivers.

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/99b7e6401ee482fa. Report an issue: GitHub.