fatedier/frp · error

client registry unavailable

Error message

client registry unavailable

What it means

The v2 API endpoint /api/v2/users aggregates clients by user via clientRegistry.List(); if the controller was built without a ClientRegistry the nil check fails and the endpoint errors out before pagination results are built.

Source

Thrown at server/http/controller_v2.go:114

		return nil, err
	}

	cleared, total := mem.StatsCollector.PruneOfflineProxies()
	return model.V2SystemPruneResp{
		Type:    pruneType,
		Cleared: cleared,
		Total:   total,
	}, nil
}

// /api/v2/users
func (c *Controller) APIV2UserList(ctx *httppkg.Context) (any, error) {
	page, pageSize, err := parseV2PageParams(ctx)
	if err != nil {
		return nil, err
	}
	if c.clientRegistry == nil {
		return nil, fmt.Errorf("client registry unavailable")
	}

	userStats := make(map[string]*model.V2UserResp)
	for _, info := range c.clientRegistry.List() {
		item := getOrCreateV2User(userStats, info.User)
		item.ClientCount++
	}
	for _, proxyInfo := range c.listV2ProxyStats("") {
		item := getOrCreateV2User(userStats, proxyInfo.User)
		item.ProxyCount++
	}

	q := strings.ToLower(ctx.Query("q"))
	items := make([]model.V2UserResp, 0, len(userStats))
	for _, item := range userStats {
		if q != "" && !strings.Contains(strings.ToLower(item.User), q) {
			continue
		}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Wire the ClientRegistry into the Controller used for v2 routes.
  2. If a registry-less deployment is intentional, disable the v2 API routes.
  3. Add constructor functions (rather than struct literals) so controllers cannot be built half-initialized.

Example fix

// before
c := &Controller{} // v2 routes registered, registry nil

// after
c := NewController(clientRegistry, proxyManager)
Defensive patterns

Strategy: validation

Validate before calling

if controller.ClientRegistry() == nil {
    return errors.New("v2 user API unavailable without registry")
}

Try / catch

// map to 503 and alert on occurrence — it signals a wiring regression, not user error

Prevention

When it happens

Trigger: A GET /api/v2/users request reaches a Controller whose clientRegistry field is nil — custom embedding, tests, or a broken bootstrap — after parseV2PageParams succeeds; the nil guard fires before any aggregation.

Common situations: Custom builds or embeddings of frps that register v2 routes but skip registry wiring; startup refactor dropping the registry argument; test controllers with partial fields.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/92963c22e721c328. Report an issue: GitHub.