gastownhall/beads · error

reading gate %s: %w

Error message

reading gate %s: %w

What it means

Wraps an unexpected error from GetIssue while reading the gate inside the AddWaiter transaction. Unlike 'gate not found', this means the lookup itself failed — a storage/backend error, not a missing issue. The original error is preserved via %w for diagnosis.

Source

Thrown at cmd/bd/gate_proxied_server.go:253

		}
	}()

	gateID := args[0]
	waiter := args[1]

	if uowProvider == nil {
		return HandleError("proxied-server UOW provider not initialized")
	}

	applied, err := uow.RunTxResult(ctx, uowProvider, func(ctx context.Context, uw uow.UnitOfWork) (gateAddWaiterApply, string, error) {
		var out gateAddWaiterApply

		issue, err := uw.IssueUseCase().GetIssue(ctx, gateID)
		if gateProxiedNotFound(err) {
			return out, "", fmt.Errorf("gate not found: %s", gateID)
		}
		if err != nil {
			return out, "", fmt.Errorf("reading gate %s: %w", gateID, err)
		}
		if issue.IssueType != "gate" {
			return out, "", fmt.Errorf("%s is not a gate issue (type=%s)", gateID, issue.IssueType)
		}

		for _, w := range issue.Waiters {
			if w == waiter {
				out.already = true
				// Empty commit message: a registered waiter is a no-op, and a
				// no-op writes no Dolt commit.
				return out, "", nil
			}
		}

		newWaiters := append(issue.Waiters, waiter)
		if err := uw.IssueUseCase().UpdateIssue(ctx, gateID, map[string]any{"waiters": newWaiters}, actor); err != nil {
			return out, "", fmt.Errorf("updating gate: %w", err)
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped cause (%w) to identify the storage failure
  2. Run `bd doctor` to validate database connectivity and health
  3. Retry the AddWaiter call — many driver/connection errors are transient
  4. If errors persist, inspect Dolt server logs and database state before further writes

Example fix

// before: no retry around the gate read
issue, err := uw.IssueUseCase().GetIssue(ctx, gateID)
if gateProxiedNotFound(err) { return out, "", fmt.Errorf("gate not found: %s", gateID) }
if err != nil { return out, "", fmt.Errorf("reading gate %s: %w", gateID, err) }
// after: caller retries transient read failures with backoff
var issue *Issue
backoff := 100 * time.Millisecond
for i := 0; i < 3; i++ {
    issue, err = client.Show(ctx, gateID)
    if err == nil { break }
    if isNotFound(err) { return err }
    time.Sleep(backoff); backoff *= 2
}
if err != nil { return fmt.Errorf("reading gate %s after retries: %w", gateID, err) }
Defensive patterns

Strategy: retry

Validate before calling

ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
_ = bdClient.Show(ctx, "bd-probe") // probe read: if this fails, storage is unhealthy

Type guard

func isTransientStorageErr(err error) bool {
    msg := err.Error()
    return strings.Contains(msg, "connection") || strings.Contains(msg, "timeout") || strings.Contains(msg, "deadline")
}

Try / catch

var issue *Issue
err := retry.Do(3, 200*time.Millisecond, func() error {
    var e error
    issue, e = client.Show(ctx, gateID)
    if e != nil && isTransientStorageErr(e) { return e }
    return retry.Stop(e)
})
if err != nil { return fmt.Errorf("reading gate %s: %w", gateID, err) }

Prevention

When it happens

Trigger: IssueUseCase().GetIssue(ctx, gateID) returns an error that is not classified as not-found (gateProxiedNotFound is false) — e.g. Dolt connection failure, transaction abort, corrupt record, or context cancellation during the read.

Common situations: Dolt server down or network partition between bd and storage; context deadline exceeded while the transaction waits on a lock; database corruption or failed migration; transient driver errors under concurrent writes.

Related errors


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