x/inference: GetAllModelCapacities keys the epoch-group map with a block height, so the query always returns empty #1725
GetAllModelCapacities reads EpochGroupDataMap with a block height where the map is keyed by epoch index, so the lookup never hits and the query returns an empty list on every call.
The mismatch
The map is written keyed by EpochIndex:
// inference-chain/x/inference/keeper/epoch_group_data.go:11
func (k Keeper) SetEpochGroupData(ctx context.Context, epochGroupData types.EpochGroupData) {
k.EpochGroupDataMap.Set(ctx, collections.Join(epochGroupData.EpochIndex, epochGroupData.ModelId), epochGroupData)
}
and read with the parameter named epochIndex:
// inference-chain/x/inference/keeper/epoch_group_data.go:16
func (k Keeper) GetEpochGroupData(ctx context.Context, epochIndex uint64, modelId string) (val types.EpochGroupData, found bool) {
val, err := k.EpochGroupDataMap.Get(ctx, collections.Join(epochIndex, modelId))
but this call site passes a block height instead:
// inference-chain/x/inference/keeper/query_dynamic_pricing.go:116
mainEpochData, found := k.GetEpochGroupData(goCtx, uint64(currentEpoch.PocStartBlockHeight), "")
Epoch.Index and Epoch.PocStartBlockHeight are different quantities on different scales — a sequential epoch counter versus a chain height — so they coincide only by accident. found is therefore false, and the handler takes its early return.
Why it is quiet
The early return is not an error:
// query_dynamic_pricing.go:117
if !found {
k.LogError("Failed to get epoch group data for capacity query", types.Pricing)
return &types.QueryGetAllModelCapacitiesResponse{
ModelCapacities: modelCapacities, // nil
}, nil
}
so the RPC answers 200 with an empty list rather than surfacing a failure, and every consumer sees a well-formed "no capacities" response.
Consumers that cannot tell the difference
common/queryapi/models.go:227 collapses both cases into an empty map, by its own documented contract ("Returns an empty map if the query fails or returns no data"):
resp, err := qc.GetAllModelCapacities(ctx, &inferencetypes.QueryGetAllModelCapacitiesRequest{})
if err != nil || len(resp.ModelCapacities) == 0 {
return map[string]int{}
}
decentralized-api/internal/server/public/get_pricing_handler.go:92 builds its per-model metrics map by ranging over the same empty slice, so Capacity and Utilization are absent for every model. That handler serves the live route registered at decentralized-api/internal/server/public/server.go:112:
So the visible effect is that governance pricing reports no per-model capacity, and nothing distinguishes that from genuinely having none.
Suggested fix
The immediate one is the key at the call site:
The durable one is a naming change nearby, because this call site is a reasonable misreading rather than a typo. getEpochGroupWeightData(ctx, pocStartHeight uint64, ...) in the reward path declares a parameter called pocStartHeight that its callers correctly fill with msg.EpochIndex. Anyone reading that signature would conclude the map is keyed by height. Renaming that parameter to epochIndex removes the trap; grepping for other callers passing a height is worth doing in the same pass.
Separately, the two consumers above would be more honest distinguishing a failed query from an empty result, so a future regression of this kind surfaces instead of rendering as zero.
What I verified, and what I did not
Verified by reading main at 379bebced6: the write key, the read key, the call site, the two consumers, and the route registration. I also searched open issues and pull requests for GetAllModelCapacities and all-model-capacities and found nothing covering this.
Not verified today: the live response. node1.gonka.ai:8000 and node2.gonka.ai:8000 both returned nginx 503 on /chain-api/productscience/inference/inference/all_model_capacities across repeated attempts while I was writing this, so I could not re-confirm the empty result against mainnet in this pass. An earlier observation of mine on 2026-08-28 recorded {} from that endpoint, but I am flagging it as dated rather than presenting it as a current measurement. The code path above does not depend on that confirmation.
💬 Comments (1)
🔄 Auto-synced from Issue #1725 every hour.
Closing the caveat I left at the end of the report: the live confirmation now exists.
node1.gonka.aiwas returning nginx503while I was writing, and it is intermittent rather than down — it answered on a retry.Mainnet, epoch 386:
The two key values are in the same response and differ by four orders of magnitude, which is the whole defect in one line:
EpochGroupDataMapis keyed by386, and the query looks it up with5952281.The empty list is worth separating from an honest empty, since the two are indistinguishable at the API. Four models are in the epoch group, so there was something to iterate; and the handler returns before reaching the loop, because
GetEpochGroupDatareports not-found and it takes the early return. So[]here is the miss, not a true "no model has capacity set".