dgraph-io/dgraph · error

%s: %s

Error message

%s: %s

What it means

resolveState calls the edgraph Server's State method to fetch the cluster membership state; any error from that call is re-wrapped as '<x.Error>: <detail>' and returned as an empty GraphQL result. The wrapper preserves the underlying detail (Raft/health check failure) so the suffix tells you what actually broke. This is about the /state-equivalent admin GraphQL query failing at the server layer.

Source

Thrown at graphql/admin/state.go:46

	MaxTxnTs   uint64         `json:"maxTxnTs,omitempty"`
	MaxRaftId  uint64         `json:"maxRaftId,omitempty"`
	Removed    []*pb.Member   `json:"removed,omitempty"`
	Cid        string         `json:"cid,omitempty"`
	Namespaces []uint64       `json:"namespaces,omitempty"`
}

type clusterGroup struct {
	Id         uint32       `json:"id,omitempty"`
	Members    []*pb.Member `json:"members,omitempty"`
	Tablets    []*pb.Tablet `json:"tablets,omitempty"`
	SnapshotTs uint64       `json:"snapshotTs,omitempty"`
	Checksum   uint64       `json:"checksum,omitempty"`
}

func resolveState(ctx context.Context, q schema.Query) *resolve.Resolved {
	resp, err := (&edgraph.Server{}).State(ctx)
	if err != nil {
		return resolve.EmptyResult(q, errors.Errorf("%s: %s", x.Error, err.Error()))
	}

	// unmarshal it back to MembershipState proto in order to map to graphql response
	var ms pb.MembershipState
	if err := protojson.Unmarshal(resp.GetJson(), &ms); err != nil {
		return resolve.EmptyResult(q, err)
	}

	ns, _ := x.ExtractNamespace(ctx)
	// map to graphql response structure. Only superadmin can list the namespaces.
	state := convertToGraphQLResp(&ms, ns == x.RootNamespace)
	b, err := json.Marshal(state)
	if err != nil {
		return resolve.EmptyResult(q, err)
	}
	var resultState map[string]interface{}
	err = schema.Unmarshal(b, &resultState)
	if err != nil {

View on GitHub (pinned to 759e242be6)

Solutions

  1. Read the text after the prefix for the root cause (e.g. no connected Zero, raft: no leader) and address it directly.
  2. Verify Zero nodes are running and reachable from this Alpha (check --zero addresses, DNS, ports 5080/6080).
  3. Wait for the Alpha to finish joining/replaying and re-run the state query.
  4. Use curl on /health and /state HTTP endpoints to triage cluster membership.
  5. If the node was removed from the cluster, re-add it or point clients at a healthy member.

Example fix

// before: querying an Alpha whose Zero is down
query { state { ... } }  // -> "x: ...connection refused..."
// after: restore Zero, then
query { state { groups { id } } }
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check cluster health before the state query
const health = await fetch('http://alpha:8080/health').then(r => r.json());
if (!health.every(h => h.status === 'healthy')) throw new Error('cluster unhealthy; skip state query');

Try / catch

try {
  return await gql(stateQuery);
} catch (e) {
  if (String(e.message).includes('x:')) {
    const detail = e.message.split(': ').slice(1).join(': ');
    if (/connection refused|no leader|unavailable/i.test(detail)) {
      await sleep(backoff);
      return retry(() => gql(stateQuery), 3); // transient cluster state
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: Querying state via the admin GraphQL API when the internal Server.State call fails: the node is not part of a healthy cluster, Raft has no leader, the node is still starting up, or internal gRPC connections to Zero/other Alphas are down.

Common situations: Querying a freshly restarted Alpha before it rejoining the group, Zero down or unreachable (bad zeroDir/--zero flags), network partitions in Kubernetes, or hitting an Alpha that was removed from the cluster.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/1239c4c758d7c974. Report an issue: GitHub.