{"record":{"id":"6d53594dd24829f8","repo":"gastownhall/beads","slug":"reading-gate-s-w","errorCode":null,"errorMessage":"reading gate %s: %w","messagePattern":"reading gate (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/gate_proxied_server.go","lineNumber":253,"sourceCode":"\t\t}\n\t}()\n\n\tgateID := args[0]\n\twaiter := args[1]\n\n\tif uowProvider == nil {\n\t\treturn HandleError(\"proxied-server UOW provider not initialized\")\n\t}\n\n\tapplied, err := uow.RunTxResult(ctx, uowProvider, func(ctx context.Context, uw uow.UnitOfWork) (gateAddWaiterApply, string, error) {\n\t\tvar out gateAddWaiterApply\n\n\t\tissue, err := uw.IssueUseCase().GetIssue(ctx, gateID)\n\t\tif gateProxiedNotFound(err) {\n\t\t\treturn out, \"\", fmt.Errorf(\"gate not found: %s\", gateID)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn out, \"\", fmt.Errorf(\"reading gate %s: %w\", gateID, err)\n\t\t}\n\t\tif issue.IssueType != \"gate\" {\n\t\t\treturn out, \"\", fmt.Errorf(\"%s is not a gate issue (type=%s)\", gateID, issue.IssueType)\n\t\t}\n\n\t\tfor _, w := range issue.Waiters {\n\t\t\tif w == waiter {\n\t\t\t\tout.already = true\n\t\t\t\t// Empty commit message: a registered waiter is a no-op, and a\n\t\t\t\t// no-op writes no Dolt commit.\n\t\t\t\treturn out, \"\", nil\n\t\t\t}\n\t\t}\n\n\t\tnewWaiters := append(issue.Waiters, waiter)\n\t\tif err := uw.IssueUseCase().UpdateIssue(ctx, gateID, map[string]any{\"waiters\": newWaiters}, actor); err != nil {\n\t\t\treturn out, \"\", fmt.Errorf(\"updating gate: %w\", err)\n\t\t}","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/gate_proxied_server.go#L235-L271","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the wrapped cause (%w) to identify the storage failure","Run `bd doctor` to validate database connectivity and health","Retry the AddWaiter call — many driver/connection errors are transient","If errors persist, inspect Dolt server logs and database state before further writes"],"exampleFix":"// before: no retry around the gate read\nissue, err := uw.IssueUseCase().GetIssue(ctx, gateID)\nif gateProxiedNotFound(err) { return out, \"\", fmt.Errorf(\"gate not found: %s\", gateID) }\nif err != nil { return out, \"\", fmt.Errorf(\"reading gate %s: %w\", gateID, err) }\n// after: caller retries transient read failures with backoff\nvar issue *Issue\nbackoff := 100 * time.Millisecond\nfor i := 0; i < 3; i++ {\n    issue, err = client.Show(ctx, gateID)\n    if err == nil { break }\n    if isNotFound(err) { return err }\n    time.Sleep(backoff); backoff *= 2\n}\nif err != nil { return fmt.Errorf(\"reading gate %s after retries: %w\", gateID, err) }","handlingStrategy":"retry","validationCode":"ctx, cancel := context.WithTimeout(ctx, 10*time.Second)\ndefer cancel()\n_ = bdClient.Show(ctx, \"bd-probe\") // probe read: if this fails, storage is unhealthy","typeGuard":"func isTransientStorageErr(err error) bool {\n    msg := err.Error()\n    return strings.Contains(msg, \"connection\") || strings.Contains(msg, \"timeout\") || strings.Contains(msg, \"deadline\")\n}","tryCatchPattern":"var issue *Issue\nerr := retry.Do(3, 200*time.Millisecond, func() error {\n    var e error\n    issue, e = client.Show(ctx, gateID)\n    if e != nil && isTransientStorageErr(e) { return e }\n    return retry.Stop(e)\n})\nif err != nil { return fmt.Errorf(\"reading gate %s: %w\", gateID, err) }","preventionTips":["Ensure the Dolt server/storage backend is reachable before gate operations (bd doctor)","Set explicit context timeouts so reads fail fast with a clear cause","Retry transient connection errors with backoff before giving up","Watch for lock contention from concurrent bd writers during transactions"],"tags":["storage","gate","transaction","dolt"],"backgroundTag":"storage-read-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}