Configuration Status
AISIX AI Gateway reports whether its configuration took effect — and if not, why — through its status endpoints and a set of Prometheus metrics. Together they answer the operator question "is the gateway serving the configuration I intended?" for every configuration source: a resources.yaml file, a self-managed configuration store, or the managed control plane.
These endpoints are served on the dedicated metrics listener, observability.metrics.prometheus.addr (default 0.0.0.0:9090), alongside GET /metrics. Like the metrics endpoint, they are unauthenticated by design; keep the listener private to your monitoring network. The admin listener does not serve these routes.
| Endpoint | Purpose |
|---|---|
GET /status/config | Full configuration load state: derived state, source and applied hashes, resource counts, reload results, and rejected entries. |
GET /status/ready | Readiness gate: 503 until the first valid configuration is applied, 200 ok afterward. |
GET /status/models | Per-model runtime health: one row per configured model with its rotation status. |
GET /status/config
Returns a JSON document describing the last observed and last applied configuration:
curl -sS "http://127.0.0.1:9090/status/config"
{
"state": "synced",
"source": {
"type": "file",
"source_hash": "1dc0ee8d06edcde3ecbf23672858622a83f266910846f514ccb909cf41046653",
"observed_at": "2026-07-16T07:14:30Z"
},
"applied": {
"config_hash": "1dc0ee8d06edcde3ecbf23672858622a83f266910846f514ccb909cf41046653",
"apply_seq": 1,
"applied_at": "2026-07-16T07:14:30Z",
"resource_counts": {
"api_keys": 1,
"models": 1,
"provider_keys": 1
}
},
"last_reload": {
"successful": true,
"at": "2026-07-16T07:14:30Z"
},
"last_failure": null,
"rejected": []
}
Configuration States
state is derived by the gateway from the last observed and applied snapshots:
| State | Meaning |
|---|---|
synced | The applied configuration matches the latest snapshot observed from the source, and nothing was rejected. |
degraded | The gateway is serving, but the latest snapshot carried entries it rejected. The accepted subset is applied; the rejected array names what was dropped. |
out_of_sync | The latest observed snapshot was rejected as a whole. The gateway keeps serving the last valid configuration. |
empty | A valid configuration was applied, but it holds zero resources. |
never_loaded | No valid configuration has been applied since the process started. |
A gateway configured from a resources file applies the file all or nothing, so a failed file reload reports out_of_sync rather than degraded. degraded occurs when the source delivers resources individually and only some of them are invalid.
Response Fields
Top-level fields:
| Field | Type | Description |
|---|---|---|
state | string | Derived configuration state. One of synced, degraded, out_of_sync, empty, never_loaded. |
source | object | The latest snapshot observed from the configuration source. |
applied | object | The last configuration actually applied and served. Omitted while state is never_loaded. |
last_reload | object | Outcome of the most recent load. Omitted before the first load completes. |
last_failure | object or null | The most recent load failure since the process started. Sticky: it remains populated after a later successful reload, until restart. |
rejected | array | Entries the gateway rejected from the latest snapshot. Empty when everything loaded. |
source fields:
| Field | Type | Description |
|---|---|---|
type | string | Where configuration is read from: file or etcd. |
connected | boolean | Whether the configuration store is reachable. Present only when type is etcd. |
observed_revision | number | Store revision of the latest observed snapshot. Present only when type is etcd. |
source_hash | string | SHA-256 hash of the latest observed snapshot. For a file source, this is the hash of the raw file bytes. |
observed_at | string | RFC 3339 UTC timestamp of the latest observation. |
applied fields:
| Field | Type | Description |
|---|---|---|
applied_revision | number | Store revision the applied configuration reflects. Present only when source.type is etcd. |
config_hash | string | SHA-256 hash of the accepted, served configuration. Equal to source_hash when nothing was rejected. |
apply_seq | number | Counter that increments each time the applied configuration changes. Unchanged content does not advance it. |
applied_at | string | RFC 3339 UTC timestamp of the last applied change. |
resource_counts | object | Served resource count per kind, for example {"models": 2}. |
last_reload and last_failure fields:
| Field | Type | Description |
|---|---|---|
last_reload.successful | boolean | Whether the most recent load completed without rejections. |
last_reload.at | string | RFC 3339 UTC timestamp of the most recent load. |
last_failure.at | string | When the most recent failure occurred. |
last_failure.last_error_kind | string | Failure kind of the most recent failure. |
last_failure.last_error | string | Human-readable message of the most recent failure. |
Each entry in rejected:
| Field | Type | Description |
|---|---|---|
resource_kind | string | Plural resource kind, such as models or provider_keys. Empty when the source entry could not be attributed to a kind. |
resource_id | string | Resource ID. Empty when the source entry could not be parsed far enough to identify it. |
last_error_kind | string | Failure kind: bad_key, non_json, schema_failed, parse_failed, or unknown_kind. |
last_error | string | Human-readable error. Schema messages mask credential values. |
first_seen_at | string | When this rejection was first observed since the process started. Stable across repeated reloads of the same bad entry. |
last_seen_at | string | When this rejection was most recently observed. |
Use config_hash to confirm a specific change landed: the hash is deterministic, so a deployment pipeline that knows what it shipped can compare hashes instead of diffing resources. For a file source, source_hash is the SHA-256 of the file bytes (sha256sum resources.yaml).
GET /status/ready
A readiness gate for the configuration source only:
curl -sSi "http://127.0.0.1:9090/status/ready"
| Condition | Status | Body |
|---|---|---|
| No valid configuration applied yet | 503 Service Unavailable | no configuration available |
| A valid configuration has been applied | 200 OK | ok |
Use it as a startup or readiness probe so a gateway does not receive traffic before it can serve configured routes. It stays 200 once the first configuration is applied, including while a later reload fails and the gateway serves the last valid configuration. The proxy listener's /livez and /readyz keep their process-level semantics; see Troubleshooting.
GET /status/models
The per-model runtime health view — one row per configured model:
curl -sS "http://127.0.0.1:9090/status/models"
[
{
"id": "9a3f2c67-52b8-4b1e-9f4e-1f2f3a4b5c6d",
"display_name": "gpt-4o-prod",
"kind": "direct",
"status": "healthy"
},
{
"id": "5b17e9d2-8a44-4c05-b7a1-0c9d8e7f6a5b",
"display_name": "claude-prod",
"kind": "direct",
"status": "cooldown",
"status_reason": "upstream_auth_failure",
"cooldown_until": { "secs_since_epoch": 1784708130, "nanos_since_epoch": 0 }
}
]
| Status | Meaning |
|---|---|
healthy | The model is in rotation. |
cooldown | Recent upstream failures took the model out of rotation until cooldown_until; status_reason names the failure class, for example upstream_auth_failure or upstream_rate_limited. |
unhealthy | Recent background model checks failed; routing avoids the model. last_check_status carries the HTTP status of the most recent check. |
not_applicable | The row is a multi-target or other virtual model; its availability derives from its target models' rows. |
Timestamps (cooldown_until, and last_checked_at on background-checked models) are seconds/nanoseconds epoch objects as shown above, not RFC 3339 strings. Like the other status endpoints, /status/models is unauthenticated and reflects the applied configuration, so it keeps working in every deployment mode.
Configuration Load Metrics
The GET /metrics endpoint on the same listener exposes the configuration load state as Prometheus series. Values refresh at scrape time from the same state that backs GET /status/config.
| Metric | Type | Labels | Description |
|---|---|---|---|
aisix_config_last_reload_successful | gauge | None | 1 when the most recent load completed without rejections, otherwise 0. |
aisix_config_last_reload_success_timestamp_seconds | gauge | None | Unix timestamp of the most recent successful load. |
aisix_config_reloads_total | counter | None | Configuration loads since the process started, counting boot loads, file reloads, and full synchronizations from the configuration store. |
aisix_config_reload_failures_total | counter | reason | Loads that did not fully succeed, bucketed by reason: fetch (source unreachable or unreadable), parse (source content could not be parsed), or validate (a resource failed schema, shape, or reference validation). |
aisix_config_rejected_resources | gauge | kind | Currently rejected entries per resource kind. 0 after the offending entries are fixed. |
aisix_config_hash_info | gauge | hash | Info-style series: exactly one live sample with value 1, whose hash label is the applied config_hash. |
aisix_config_observed_revision | gauge | None | Store revision of the latest observed snapshot. Emitted only for an etcd source. |
aisix_config_applied_revision | gauge | None | Store revision of the applied configuration. Emitted only for an etcd source. |
aisix_config_source_connected | gauge | None | 1 when the configuration store is reachable. Emitted only for an etcd source. |
For the full metric catalog, see Metrics Reference.
Example Alerts
Alert when the gateway rejects any configured resource — the gateway keeps serving, but something an operator wrote is not in effect:
- alert: AisixConfigRejectedResources
expr: sum by (instance) (aisix_config_rejected_resources) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "AISIX gateway is rejecting configured resources"
description: "Check GET /status/config on {{ $labels.instance }}: the rejected array names each entry and its error."
Alert when configuration reloads keep failing — the gateway is running on the last valid configuration and new changes are not taking effect:
- alert: AisixConfigReloadFailing
expr: aisix_config_last_reload_successful == 0
for: 10m
labels:
severity: warning
annotations:
summary: "AISIX gateway configuration reloads are failing"
description: "The last configuration load on {{ $labels.instance }} did not fully succeed. Check last_failure and rejected in GET /status/config."
Next Steps
- Understand how accepted changes reach proxy requests in Configuration Propagation.
- Reload a file-configured gateway and check the result in the Open-Source AISIX Gateway Quickstart.