gastownhall/beads · error
%s is not a gate issue (type=%s)
Error message
%s is not a gate issue (type=%s)
What it means
Thrown when the issue identified by gateID exists but its IssueType is not "gate". The AddWaiter path only accepts gate issues; attaching a waiter to any other issue type is rejected with the actual type included in the message. This is a validation error preventing waiter registration on non-gate issues.
Source
Thrown at cmd/bd/gate_proxied_server.go:256
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)
}
if after, getErr := uw.IssueUseCase().GetIssue(ctx, gateID); getErr == nil {
out.after = after
}View on GitHub (pinned to 71377f2769)
Solutions
- Confirm the correct gate ID with `bd list --type gate` and pass that ID, not a task/bug ID
- Create a gate issue for the workflow if none exists (`bd create "..." -t gate`)
- Check the issue's current type with `bd show <id>`; if it was re-typed by mistake, correct it before adding waiters
- Fix scripts to resolve the gate ID rather than hard-coding the waiter issue's ID
Example fix
// before: assumes any issue ID is a valid gate
client.AddWaiter(ctx, taskID, waiter)
// after: verify type before calling
issue, _ := client.Show(ctx, taskID)
if issue == nil || issue.IssueType != "gate" {
return fmt.Errorf("%s is not a gate issue; use bd list --type gate", taskID)
}
client.AddWaiter(ctx, taskID, waiter) Defensive patterns
Strategy: validation
Validate before calling
issue, err := bdClient.Show(ctx, gateID)
if err != nil { return err }
if issue.IssueType != "gate" {
return fmt.Errorf("%s is type %q, not gate — pick an ID from bd list --type gate", gateID, issue.IssueType)
} Type guard
func isGateIssue(issue *Issue) bool {
return issue != nil && issue.IssueType == "gate"
} Try / catch
err := client.AddWaiter(ctx, gateID, waiter)
if err != nil && strings.Contains(err.Error(), "is not a gate issue") {
return fmt.Errorf("wrong target: %v; create or locate a gate with: bd create 'wait for X' -t gate", err)
} Prevention
- Always resolve gate IDs via `bd list --type gate`, never pass task/bug IDs
- Create a dedicated gate issue when a workflow needs awaiting instead of reusing a task
- Audit scripts for hardcoded issue IDs that may point at non-gate types
- If an issue's type was changed, re-check all registered waiters against it
When it happens
Trigger: Calling AddWaiter with the ID of a task, bug, feature, epic, or chore issue; a script passes the wrong issue ID (e.g. the waiter's own ID instead of the gate's); the issue's type was changed after a waiter reference was recorded.
Common situations: Mixing up parent/child IDs in scripts; attempting to await on a regular task instead of creating a gate; older databases where the issue was created with a different type and later re-typed; copy-pasted IDs from another workflow.
Related errors
- no timeout set
- gate not found: %s
- waits-for gate %q is neither %q nor %q
- %w: invalid issue type %v
- %w: invalid issue type %s
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/fccc3b649aa25500.
Report an issue: GitHub.