gastownhall/beads · error

proxied-server provider %T does not offer the cycle-report s

Error message

proxied-server provider %T does not offer the cycle-report surface

What it means

proxiedCycleDetector performs a runtime capability check: when running against a proxied server, the UOW provider must implement uow.CycleDetectorSource to expose cycle reports. If the concrete provider type does not, this error names the offending type with %T. It is a capability-mismatch guard, not a user-input error.

Source

Thrown at cmd/bd/dep_cycles.go:34

// openCycleDetector hands back the cycle role for whichever route this
// invocation is on.
func openCycleDetector() (issueops.CycleDetector, error) {
	if usesProxiedServer() {
		return proxiedCycleDetector()
	}
	return store.CycleDetector()
}

// proxiedCycleDetector hands back the guarded cycle-report surface for the
// proxied-server provider, through the provider's own capability accessor.
func proxiedCycleDetector() (issueops.CycleDetector, error) {
	if uowProvider == nil {
		return nil, errors.New("proxied-server UOW provider not initialized")
	}
	src, ok := uowProvider.(uow.CycleDetectorSource)
	if !ok {
		return nil, fmt.Errorf("proxied-server provider %T does not offer the cycle-report surface", uowProvider)
	}
	return src.CycleDetector()
}

// runDepCycles is the whole of `bd dep cycles` on both routes.
func runDepCycles() error {
	detector, err := openCycleDetector()
	if err != nil {
		return HandleErrorRespectJSON("%v", err)
	}
	report, err := detector.DetectCycles(rootCtx, issueops.DetectCyclesRequest{})
	if err != nil {
		return HandleErrorRespectJSON("%v", err)
	}

	if jsonOutput {
		// The role's slice is empty rather than nil for an acyclic workspace, so
		// this is `[]` and never `null` without a guard here.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Upgrade the bd server (daemon) to a version whose provider implements the cycle-report surface so client and server match.
  2. Run `bd doctor` / check versions on both client and server; restart the daemon after upgrading.
  3. If using a custom provider, implement uow.CycleDetectorSource (CycleDetector() method) on the provider type.
  4. Run cycles detection locally (non-proxied) if server upgrade is not possible.

Example fix

// before: old server provider type lacks the surface
// proxied-server provider *server.LegacyProvider does not offer the cycle-report surface

// after: upgrade server binary, then restart
bd server stop && bd server start  # new provider implements uow.CycleDetectorSource
Defensive patterns

Strategy: type-guard

Validate before calling

// before invoking proxied routes, check server capability
if src, ok := uowProvider.(uow.CycleDetectorSource); !ok {
	fmt.Fprintln(os.Stderr, "server lacks cycle-report surface; upgrade bd server")
	os.Exit(1)
}

Type guard

func hasCycleDetector(p any) bool {
	_, ok := p.(uow.CycleDetectorSource)
	return ok
}

Try / catch

det, err := proxiedCycleDetector()
if err != nil {
	if strings.Contains(err.Error(), "cycle-report surface") {
		return fmt.Errorf("upgrade bd server to use `bd dep cycles`: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Running `bd dep cycles` in proxied-server mode where uowProvider is set but does not implement CycleDetectorSource; typically a beads version mismatch where the server's provider predates the cycle-report surface.

Common situations: Newer bd client against an older bd server that lacks the cycle-report capability; custom/embedded provider swapped in that only implements the base surfaces; misrouted embedded mode where uowProvider holds the wrong concrete type.

Related errors


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