Skip to content

One closed index and the storage figure becomes N/A

A failed cluster read produces no storage row at all rather than one claiming zero bytes, and a partial sum is refused for exactly the same reason.

Close one index on an OpenSearch cluster, open the monitoring surface, and the Data figure for every other index goes away with it. That is not a bug report waiting to be filed. It is the rule this provider applies everywhere it reads a number: a panel either shows a figure that means what it says, or it shows N/A and says why. A partial sum would be a measurement of the cluster that no longer describes the cluster.

The monitoring rating for this engine is partial, and the word is doing precise work. Some panels answer; some are empty because the cluster has nothing of that shape to report. Those two states are drawn differently, so an empty panel does not read as a failed one.

What answers from the cluster APIs

There is no driver here. Every statement and every monitoring read is one stateless HTTP request through the runtime’s own fetch, against port 9200 for both schemes. Monitoring reads four REST endpoints and no more: /, _cluster/health, _cluster/stats and _cat/indices.

From those, four panels come back populated:

Panel Read from What it reports
Overview /, _cluster/health, _cat/indices, _cluster/stats version, cluster health, user index count, cluster store size
Health the above, composed status colour and the size, with the unknowns carried across as unknown
Tables _cat/indices one row per user index: docs.count as rows, pri.store.size as size
Storage _cluster/health plus _cluster/stats one row for the cluster, sized from indices.store.size_in_bytes

Two counts in that overview are named for a relational world and mean something else here. tableCount counts indices, because an index is the table on this surface, and it counts the user’s indices only - the same set the schema tree shows by default, so the panel and the sidebar cannot disagree. indexCount is 0 and stays 0, because there is no secondary index object to count: every mapped field is inverted-indexed as a property of being mapped.

One number needs a caveat before it misleads someone. An index whose mapping declares nested fields reports more documents than a SELECT COUNT(*) against it returns - measured, a probe index reporting 2 documents in _cat/indices answered 1 from SQL - because every nested element is stored as a document of its own. The panel reports the cluster’s document count; the editor reports rows in a result.

Panels that are empty by construction, not unimplemented

Performance metrics, slow queries, sessions and index statistics are structurally empty here rather than unimplemented, and there is no query cancellation, because aborting only ends this client wait while the cluster finishes the statement. The deadline is one AbortSignal.timeout per operation: it closes this socket and sends the cluster no cancellation request at all. A cancel button would end your wait and change nothing about the load you were trying to shed, so there is no cancel button.

The sessions panel is the cleanest case. A request here is one HTTP request: no session, no connection catalog, nothing that could be listed. getActiveSessions() returns an empty list rather than throwing, because nothing is broken and nothing is misconfigured.

Index statistics are empty for the same reason indexCount is 0. There is no secondary-index object anywhere in this engine’s model to have statistics about.

Performance metrics return {} and ask the cluster nothing, and the empty object rather than a set of zeroes is load-bearing. Cache hit ratio is scored with a critical threshold at 80 and a direction of “below”, so a helpful zero would paint a red cache fault on every healthy cluster in the fleet. An absent ratio defaults to healthy instead, and the cards that have no measurement read N/A beside “Not measured”. Until that rule reached these tabs, a measured run on a stock 3.8.0 node showed Buffer Pool 0% and Deadlocks 0 for two fields this payload simply does not contain.

The slow-query panel is the one that is a choice rather than an impossibility, and the published empty state says so: the slow log is written to the node’s own log file, which no API returns. This product also keeps a top_queries-<date> index, which the schema tree hides as engine bookkeeping. Reading it would populate a panel for some of the connections served by this one provider implementation and leave the rest blank - a monitoring surface whose contents depend on which product answered. An honest empty panel beats a panel that is sometimes populated for reasons the user cannot see.

Why a partial sum is refused

Now the closed index. getTableStats() has required fields and optional ones, and a closed index splits them. rowCount, totalSize and totalSizeBytes are required numbers, so a closed index has nowhere to write but zero. tableSize and tableSizeBytes are optional, so they are absent instead - a zero there would be a fabricated measurement rather than a forced one.

The Storage tab then gates its cluster-wide Data figure on every index having published a size. One index without one, and the Tables card reads N/A for the whole cluster rather than summing the indices that did answer.

That costs a number people want. It buys the guarantee that when the figure is present, it covers everything. A sum over the indices that happened to answer would read as the size of the cluster, and it would be wrong by an amount nothing on screen discloses. The open-beside-closed pair is pinned in the provider’s integration test, so the aggregate is asserted rather than assumed.

No row beats a row claiming zero

_cluster/stats is heavier and more privileged than _cluster/health. A cluster that answers health and refuses stats is an ordinary configuration, not a fault, so the store-size read catches its own failure and returns null - the one swallowed failure in this provider’s monitoring. Losing the health status over a missing byte count would blank a panel that already had the important number.

What matters is what that null does next. The overview prints “N/A” for the size and omits the byte key entirely. getStorageStats() returns no row at all, rather than a row naming the cluster and claiming it stores zero bytes. The Storage tab keys its refusal off the missing key and draws that refusal, instead of a 0 B total with a 0.0% breakdown underneath it.

An earlier version paired a 0 with the "N/A" it printed from the same input: one object making two claims about one unknown. A cluster that genuinely stores nothing publishes a real 0, and keeps it.

The same encoding rule runs through the overview, in both directions. activeConnections is absent rather than 0: the cluster counts open HTTP connections per node in a stats API this seam does not call, and the shard and node counts that are here would be a different number wearing that field’s name. maxConnections is 0, correct for the opposite reason - for a ceiling, zero and absence are the same fact, so the card reads it as no published limit rather than dividing by it. uptime is “N/A”, because “0s” would claim the cluster booted this instant.

What would have to change to fill the empty panels

Two of the four empties are reachable, and they are recorded as gaps rather than as impossibilities.

Performance metrics are the closer one: those numbers exist on this product’s stats endpoints, so filling that panel means widening the seam by one call. It stays empty until that happens rather than showing plausible zeroes meanwhile. Slow queries need the same widening plus an answer to the consistency problem above.

The other two do not have a version of themselves that could arrive. Sessions and secondary-index statistics are absent from the engine’s model, not from this integration, and no amount of work here produces them.

That distinction is why the empty states are published rather than left for a reader to infer. Each page in the engine reference carries what is deliberately absent next to the transport and the port, and the monitoring surface declares which tabs an engine can fill before rendering any of them. A blank panel and a broken panel look identical on screen; the text beside them is the only thing that separates the two.