Configuration Status
The AISIX gateway reports whether its configuration took effect — and if not, why — through status endpoints and Prometheus metrics. These surfaces answer the operator question "is the gateway serving the configuration I intended?" They cover every resource source: a resources.yaml file, an etcd configuration store you manage, or the AISIX Cloud 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.
| Endpoint | Purpose |
|---|---|
GET /status/config | Full configuration load state: derived state, source and applied hashes, resource counts, reload results, rejected entries, and partially compatible resources. |
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": "YYYY-MM-DDTHH:MM:SSZ"
},
"applied": {
"config_hash": "1dc0ee8d06edcde3ecbf23672858622a83f266910846f514ccb909cf41046653",
"apply_seq": 1,
"applied_at": "YYYY-MM-DDTHH:MM:SSZ",
"resource_counts": {
"api_keys": 1,
"models": 1,
"provider_keys": 1
}
},
"last_reload": {
"successful": true,
"at": "YYYY-MM-DDTHH:MM:SSZ"
},
"last_failure": null,
"rejected": [],
"partially_compatible": []
}
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 no resource was rejected. Check partially_compatible to determine whether the gateway ignored fields it does not recognize. |
degraded | The gateway is serving, but the latest snapshot carried entries it rejected. Accepted resources and any last known good values remain in service; the rejected array explains each rejected entry. |
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.
Etcd-backed configuration reads are forward compatible. If a document contains an unrecognized field, the gateway serves the recognized fields and reports the ignored field in partially_compatible. This alone does not change state from synced. Resources-file validation remains strict, so an unknown field in a resources file rejects the whole reload.
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. |
partially_compatible | array | Served etcd resources that contain fields this gateway version does not recognize, aggregated by resource kind and field. Empty when every served document matches the gateway's schema. |
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. |
serving_stale_since | string | RFC 3339 timestamp from which the gateway has kept serving the resource's last known good value. Omitted when no previous value remains in service. |
serving_stale_age_seconds | number | Seconds elapsed since serving_stale_since, recalculated when the status is read. Omitted together with serving_stale_since. |
Each entry in partially_compatible:
| Field | Type | Description |
|---|---|---|
resource_kind | string | Plural resource kind, such as api_keys or models. |
field | string | Ignored field path. Array indexes are normalized to [], for example routing.targets[].priority. |
count | number | Served resources of this kind that contain the ignored field. |
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). For an etcd source, a matching hash does not mean every field is enforced; also require partially_compatible to be empty when exact schema compatibility matters.
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 works in every gateway deployment.
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_partially_compatible_resources | gauge | kind | Served resources carrying at least one ignored field, grouped by resource kind. A resource with several ignored fields counts once. |
aisix_config_stale_served_resources | gauge | kind | Resources whose latest source value was rejected while the last known good value remains in service, grouped by resource kind. |
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."