vitessio/vitess · error

cells can only be listed, not retrieved

Error message

cells can only be listed, not retrieved

What it means

This error comes from the vtctld HTTP API collection handler for /api/cells/. The cells endpoint is a collection (list-only): when the request path tries to GET an individual cell item (a non-empty item path after 'cells'), the handler returns this error instead of attempting a per-cell lookup, because no per-cell retrieval is implemented.

Source

Thrown at go/vt/vtctld/api.go:189

	return parts[1]
}

func unmarshalRequest(r *http.Request, v any) error {
	data, err := io.ReadAll(r.Body)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, v)
}

func initAPI(ctx context.Context, ts *topo.Server, actions *ActionRepository) {
	tabletHealthCache := newTabletHealthCache(ts)
	tmClient := tmclient.NewTabletManagerClient()

	// Cells
	handleCollection("cells", func(r *http.Request) (any, error) {
		if getItemPath(r.URL.Path) != "" {
			return nil, errors.New("cells can only be listed, not retrieved")
		}
		return ts.GetKnownCells(ctx)
	})

	// Keyspaces
	handleCollection("keyspaces", func(r *http.Request) (any, error) {
		keyspace := getItemPath(r.URL.Path)
		switch r.Method {
		case "GET":
			// List all keyspaces.
			if keyspace == "" {
				return ts.GetKeyspaces(ctx)
			}
			// Get the keyspace record.
			k, err := ts.GetKeyspace(ctx, keyspace)
			if err != nil {
				return nil, err
			}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. List all cells instead: GET /api/cells (no trailing path).
  2. For a specific cell, fetch the list and filter client-side, or use vtctldclient GetCellInfo.
  3. Use the gRPC vtctlservice (GetCellInfo RPC) if per-cell data is needed programmatically.

Example fix

// before
curl http://localhost:15000/api/cells/zone1
// after
curl http://localhost:15000/api/cells   # list only
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasSuffix(req.URL.Path, "/api/cells/") || strings.Contains(strings.TrimPrefix(req.URL.Path, "/api/cells/"), "/") {
    return fmt.Errorf("/api/cells is list-only; do not request an individual cell")
}

Try / catch

resp, err := http.Get(base + "/api/cells/zone1")
// handler returns 4xx with message 'cells can only be listed, not retrieved'
// switch to the list endpoint and filter locally
if err != nil || resp.StatusCode != http.StatusOK { /* use /api/cells */ }

Prevention

When it happens

Trigger: Issuing an HTTP GET to /api/cells/<name> (or any path with a non-empty item segment after 'cells') on the vtctld web API; e.g. curl http://vtctld:15000/api/cells/zone1.

Common situations: Scripts converted from vtctl 'GetCellInfo' style lookups hitting the HTTP API; clients assuming REST-style single-resource GET exists for cells; typos leaving a trailing path segment.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/03265b90545e60b3. Report an issue: GitHub.