---
title: "health"
description: "Returns the node's operational status and the typed condition catalog that explains it."
source: https://docs.genlayer.com/api-references/genlayer-node/ops/health
last_updated: 2026-10-20
---

# health

### health

Returns the node's operational status and the typed condition catalog that explains it.

**Method:** `GET /health`

**Parameters:** None

**Returns:** JSON object containing the overall status, network/version information, validator identity (validator mode), and the full condition catalog

**HTTP status:** `503` when `status` is `unavailable`; `200` for every other state.

**Example Request:**

```bash
curl -X GET http://localhost:9153/health
```

**Example Response:**

```json
{
  "status": "healthy",
  "network": "",
  "node_version": "v0.6.0",
  "protocol_version": "0.3.0",
  "genvm_version": "v0.0.18",
  "validator_address": "0x1234567890abcdef1234567890abcdef12345678",
  "validator_moniker": "my-validator",
  "conditions": {
    "chain.rpc":                { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "chain.websocket":          { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "chain.sync":               { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:02:14Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "consensus.ban":            { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "consensus.stake":          { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "consensus.operator_funds": { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "consensus.prime":          { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:04:41Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "genvm.llm":                { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:31Z", "updated_at": "2026-09-01T10:29:56Z", "last_ok": "2026-09-01T10:29:56Z" },
    "genvm.web":                { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:31Z", "updated_at": "2026-09-01T10:29:56Z", "last_ok": "2026-09-01T10:29:56Z" },
    "node.disk":                { "state": "healthy", "severity": "critical", "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" },
    "node.snapshot_age":        { "state": "healthy", "severity": "info",     "occurrences": 0, "consecutive_failures": 0, "since": "2026-09-01T08:00:03Z", "updated_at": "2026-09-01T10:31:12Z", "last_ok": "2026-09-01T10:31:12Z" }
  }
}
```

**Response Fields:**

- `status` (string): the most urgent state across the catalog — `unknown`, `healthy`, `suspect`, `warning`, `degraded`, or `unavailable`
- `network` (string): The network the node is connected to
- `node_version`, `protocol_version`, `genvm_version` (string): build versions
- `validator_address` (string, validator mode only): The validator's address
- `validator_moniker` (string, validator mode only): The validator's on-chain moniker; reported alongside the address even when empty
- `conditions` (object): the full catalog. Every entry is always present — this is not a list of what is broken.
  - `state` (string): current state
  - `severity` (string): the catalog's fixed class — `info`, `warning`, or `critical`. Not the state: a `critical` condition can be `healthy`.
  - `occurrences` (number): accepted failed observations since process start
  - `consecutive_failures` (number): current failure streak; zero after recovery
  - `since`, `updated_at`, `last_ok` (string, optional): ISO 8601 lifecycle timestamps
  - `reason` (string, present only when not healthy): stable, low-cardinality cause code
  - `impact` (string, present only when not healthy): what the fault does to this node
  - `action` (string, present only when not healthy): what the operator should do
  - `details` (object, present only when not healthy): typed fields explicitly allowlisted by the catalog entry. Raw provider payloads, prompts, credentials, URLs, and stack traces are rejected.

**States**

| State | Meaning | Alerted |
|---|---|---|
| `unknown` | The node never observed this condition. | no |
| `healthy` | The last observation succeeded. | no |
| `suspect` | One failure, not yet confirmed. It may clear by itself. | no |
| `warning` | The capability works, and it is confirmed sub-optimal. | yes |
| `degraded` | The failure is confirmed. The capability does not work. | yes |
| `unavailable` | The node cannot do its duty at all. | yes |

Roll-up precedence, most urgent first: `unavailable`, `degraded`, `warning`, `suspect`, `unknown`, `healthy`.

`unknown` is not on that ladder. It is only ever the state a condition starts in, so it means "not observed yet", never "faulty". A GenVM module rests there until a transaction needs one; `node.snapshot_age` rests there on a node that takes no snapshots. Letting either gate the endpoint would report `unknown` for a node where nothing is wrong.

If **no** condition has been observed at all, `status` is `unknown` — nothing observed is not the same as nothing wrong.

**Only `unavailable` returns 503.**

A condition can never exceed the liveness cap its catalog entry declares. The GenVM conditions are capped at `degraded`, so a dead LLM provider returns **200**: that node is still booted, synced and voting — it votes Timeout on the transactions it cannot execute, which is the designed behaviour rather than an outage. Failing the endpoint would pull a working validator out of a load balancer.

`consensus.ban`, `consensus.stake`, `chain.rpc`, `chain.websocket` and `chain.sync` are capped at `unavailable`, because each of them stops the node doing its job.

**Example: the LLM provider is dead — HTTP 200**

```json
{
  "status": "degraded",
  "conditions": {
    "genvm.llm": {
      "state": "degraded",
      "severity": "critical",
      "reason": "llm_request_failed",
      "impact": "This validator cannot execute a transaction that needs an LLM. It votes Timeout, and the consensus contracts may penalize a Timeout vote.",
      "action": "Check the affected LLM provider service and payment or billing status, restore access, or configure a working fallback. If credentials are changed through .env, restart the node.",
      "occurrences": 2,
      "consecutive_failures": 2,
      "since": "2026-09-01T10:30:45Z",
      "updated_at": "2026-09-01T10:31:12Z",
      "last_ok": "2026-09-01T04:12:03Z"
    }
  }
}
```

**Example: the validator is banned — HTTP 503**

```json
{
  "status": "unavailable",
  "conditions": {
    "consensus.ban": {
      "state": "unavailable",
      "severity": "critical",
      "reason": "validator_banned",
      "impact": "The consensus contracts do not select this validator for a round. The node earns nothing.",
      "action": "Wait for the stated epoch. If the ban is permanent, restake with a new validator.",
      "details": { "until_epoch": "4182", "permanent": "false" },
      "occurrences": 1,
      "consecutive_failures": 1,
      "since": "2026-09-01T09:14:02Z",
      "updated_at": "2026-09-01T10:31:12Z",
      "last_ok": "2026-09-01T09:13:52Z"
    }
  }
}
```

**`chain.sync` — 503 only when the node stops syncing**

Depth is not a fault. A node syncing from genesis is millions of blocks behind and perfectly healthy. What matters is whether the stored synced block advances.

| Reason | State | HTTP |
|---|---|---|
| `sync_lagging` | `warning` | 200 |
| `sync_catching_up` | `degraded` | 200 |
| `sync_stalled` | `unavailable` | **503** |
| `sync_feed_frozen` | `unavailable` | **503** |

The node never skips a duty because it is behind. It votes Timeout only on a transaction that reads state it has not synced; a new contract deploy still runs.

**cURL Example with Headers:**

```bash
curl -X GET http://localhost:9153/health \
  -H "Accept: application/json" \
  -v
```
