gastownhall/beads · error

waits-for gate %q is neither %q nor %q

Error message

waits-for gate %q is neither %q nor %q

What it means

After unmarshalling waits-for metadata, the gate field must be one of the two supported gate kinds: WaitsForAllChildren or WaitsForAnyChildren. This error means the gate value supplied is something else (empty is auto-defaulted to all-children, so this fires only for unrecognized non-empty values).

Source

Thrown at internal/storage/batch_apply.go:384

		if trimmed == "" {
			return "", nil
		}
		if !json.Valid([]byte(trimmed)) {
			return "", fmt.Errorf("edge metadata is not well-formed JSON")
		}
		return metadata, nil
	}
	meta := types.WaitsForMeta{}
	if trimmed != "" && trimmed != "{}" {
		if err := json.Unmarshal([]byte(trimmed), &meta); err != nil {
			return "", fmt.Errorf("waits-for metadata is not a well-formed gate object: %w", err)
		}
	}
	if meta.Gate == "" {
		meta.Gate = types.WaitsForAllChildren
	}
	if !types.IsValidWaitsForGate(meta.Gate) {
		return "", fmt.Errorf("waits-for gate %q is neither %q nor %q",
			meta.Gate, types.WaitsForAllChildren, types.WaitsForAnyChildren)
	}
	raw, err := json.Marshal(meta)
	if err != nil {
		return "", fmt.Errorf("serializing waits-for metadata: %w", err)
	}
	return string(raw), nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use the exported constants types.WaitsForAllChildren or types.WaitsForAnyChildren as the gate value
  2. Check the exact constant strings with godoc or grep before writing gate names by hand
  3. Drop the gate field entirely — empty is defaulted to WaitsForAllChildren

Example fix

// before
meta := `{"gate":"all"}`
// after
meta := fmt.Sprintf(`{"gate":%q}`, types.WaitsForAllChildren)
Defensive patterns

Strategy: validation

Validate before calling

if g := meta.Gate; g != "" && !types.IsValidWaitsForGate(g) {
	return fmt.Errorf("unsupported gate %q", g)
}

Type guard

func gateKnown(s string) bool { return s == "" || types.IsValidWaitsForGate(s) }

Try / catch

if err != nil && strings.HasPrefix(err.Error(), "waits-for gate ") {
	// rewrite gate to types.WaitsForAllChildren and retry
}

Prevention

When it happens

Trigger: Supplying waits-for metadata with gate set to an unknown string such as "all", "any-child", "first", or a typo like "allchildren".

Common situations: Free-text gate names from CLI flags or config; renaming/refactoring of gate constants leaving stale stored values; copying examples from older docs.

Related errors


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