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

  1. Confirm the correct gate ID with `bd list --type gate` and pass that ID, not a task/bug ID
  2. Create a gate issue for the workflow if none exists (`bd create "..." -t gate`)
  3. Check the issue's current type with `bd show <id>`; if it was re-typed by mistake, correct it before adding waiters
  4. 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

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


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