gastownhall/beads · error

proxied-server provider %T does not offer the batch-close su

Error message

proxied-server provider %T does not offer the batch-close surface

What it means

A capability-mismatch guard in proxied-server mode: the injected unit-of-work provider does not implement `uow.BatchCloserSource`, so no batch-closer surface can be obtained. This indicates a wiring/version mismatch between the CLI command and the provider that the server assembled.

Source

Thrown at cmd/bd/close_proxied_server.go:217

	if in.session == "" {
		in.session = os.Getenv("CLAUDE_SESSION_ID")
	}
	in.jsonOut, _ = cmd.Flags().GetBool("json")
	return in
}

// proxiedBatchCloser hands back the guarded close-many surface for the
// proxied-server provider, through the provider's OWN capability accessor —
// the same two-step proxiedIssueReader performs, and for the same reason: the
// accessor is where each layer is added, so a command that reached for the
// constructor would get an unlayered closer.
func proxiedBatchCloser() (issueops.BatchCloser, error) {
	if uowProvider == nil {
		return nil, errors.New("proxied-server UOW provider not initialized")
	}
	src, ok := uowProvider.(uow.BatchCloserSource)
	if !ok {
		return nil, fmt.Errorf("proxied-server provider %T does not offer the batch-close surface", uowProvider)
	}
	return src.BatchCloser()
}

// closeProxiedRunPreflight resolves every argument and applies the CLI's own
// close policy to it, in one read-only unit of work.
func closeProxiedRunPreflight(ctx context.Context, args, reasons []string, in closeProxiedInput) (closeProxiedPreflight, error) {
	pre := closeProxiedPreflight{
		errors: make([]string, len(args)),
		before: make(map[string]*types.Issue, len(args)),
	}
	_, err := uow.RunTxRead(ctx, uowProvider, func(ctx context.Context, uw uow.UnitOfWork) (struct{}, error) {
		for i, id := range args {
			refusal, current := closeProxiedCheckOne(ctx, uw, id, in)
			if refusal != "" {
				pre.errors[i] = refusal
				continue
			}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Rebuild the bd binary and the proxied server from the same commit so interfaces match
  2. Check the provider type reported in the message (%T) against uow.BatchCloserSource and update the provider to implement it
  3. Pin client and server to the same version in your deployment
  4. Fall back to non-proxied close (run close locally against the store) if the server cannot be upgraded

Example fix

// before
src, ok := uowProvider.(uow.BatchCloserSource) // ok == false
// after
// implement the surface on the provider:
func (p *MyProvider) BatchCloser() (issueops.BatchCloser, error) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure client/server parity
bd --version  # compare with server version before proxied ops

Type guard

// check the surface before relying on proxied batch close
if _, ok := provider.(uow.BatchCloserSource); !ok {
    // fall back to local close
}

Try / catch

if err := runClose(); strings.Contains(err.Error(), "does not offer the batch-close surface") {
    // rebuild/upgrade server, or close locally
}

Prevention

When it happens

Trigger: Running a batch close through the proxied-server path when the configured uowProvider is a narrower provider type lacking BatchCloser() — typically a stale binary, mixed-version server/client, or custom provider that only implements a subset of sources.

Common situations: Server and `bd` CLI built from different commits; a plugin/custom provider compiled against an older interface that predates the batch-close surface.

Related errors


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