gastownhall/beads · error

deferred parents: check %s: %w

Error message

deferred parents: check %s: %w

What it means

Wraps an unexpected error from the deferred-parent existence probe in anyFutureDeferredParent, which checks `issues` then `wisps` for any row with defer_until in the future. ErrNoRows and missing-table errors are tolerated (the probe just moves on); anything else is fatal and wrapped here with the table name. This protects ready work from silently proceeding with an unknown deferred set.

Source

Thrown at internal/storage/domain/db/ready_work.go:86

		return nil, err
	}
	return r.descendantsOfFutureDeferredParents(ctx)
}

func (r *issueSQLRepositoryImpl) anyFutureDeferredParent(ctx context.Context) (bool, error) {
	for _, table := range []string{"issues", "wisps"} {
		var probe int
		//nolint:gosec // G201: table is a hardcoded constant.
		err := r.runner.QueryRowContext(ctx, fmt.Sprintf(
			`SELECT 1 FROM %s WHERE defer_until IS NOT NULL AND defer_until > UTC_TIMESTAMP() LIMIT 1`,
			table)).Scan(&probe)
		switch {
		case err == nil:
			return true, nil
		case errors.Is(err, sql.ErrNoRows), dberrors.IsTableNotExist(err):
			continue
		default:
			return false, fmt.Errorf("deferred parents: check %s: %w", table, err)
		}
	}
	return false, nil
}

func (r *issueSQLRepositoryImpl) descendantsOfFutureDeferredParents(ctx context.Context) ([]string, error) {
	var childIDs []string
	for _, e := range deferredParentEdges {
		//nolint:gosec // G201: depTable/issueTable/targetCol are hardcoded.
		q := fmt.Sprintf(`
			SELECT dep.issue_id
			FROM %s dep
			JOIN %s parent ON parent.id = dep.%s
			WHERE dep.type = 'parent-child'
			  AND parent.defer_until IS NOT NULL
			  AND parent.defer_until > UTC_TIMESTAMP()
		`, e.depTable, e.issueTable, e.targetCol)
		rows, err := r.runner.QueryContext(ctx, q)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error and the probed table name to pinpoint the cause
  2. Fix connectivity/credentials so SELECT on issues/wisps works
  3. Verify table integrity/schema for the probed table
  4. Retry once transient server issues clear
Defensive patterns

Strategy: retry

Validate before calling

// check connectivity and SELECT grants before ready-work calls
if err := db.PingContext(ctx); err != nil { return err }
var probe int
if err := db.QueryRow("SELECT 1 FROM issues LIMIT 1").Scan(&probe); err != nil {
	return fmt.Errorf("no SELECT access to issues: %w", err)
}

Type guard

func isDeferredProbeError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "deferred parents: check ")
}

Try / catch

ready, err := repo.GetReadyWork(ctx, filter)
if isDeferredProbeError(err) {
	// transient server/permission issue: back off and retry, or surface to ops
	time.Sleep(backoff)
	ready, err = repo.GetReadyWork(ctx, filter)
}

Prevention

When it happens

Trigger: Running the ready-work deferred-parent check when the probe SELECT against `issues` or `wisps` fails with something other than ErrNoRows/TableNotExist — e.g. connection refused, permission denied, or SQL syntax/engine error.

Common situations: Revoked DB credentials lacking SELECT on the probed table; server outage mid-check; schema corruption; engine errors like UTC_TIMESTAMP unavailability in odd configurations.

Related errors


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