Skip to main content

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.

EndpointPurpose
GET /status/configFull configuration load state: derived state, source and applied hashes, resource counts, reload results, and rejected entries.
GET /status/readyReadiness gate: 503 until the first valid configuration is applied, 200 ok afterward.
GET /status/modelsPer-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:

StateMeaning
syncedThe applied configuration matches the latest snapshot observed from the source, and nothing was rejected.
degradedThe 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_syncThe latest observed snapshot was rejected as a whole. The gateway keeps serving the last valid configuration.
emptyA valid configuration was applied, but it holds zero resources.
never_loadedNo 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:

FieldTypeDescription
statestringDerived configuration state. One of synced, degraded, out_of_sync, empty, never_loaded.
sourceobjectThe latest snapshot observed from the configuration source.
appliedobjectThe last configuration actually applied and served. Omitted while state is never_loaded.
last_reloadobjectOutcome of the most recent load. Omitted before the first load completes.
last_failureobject or nullThe most recent load failure since the process started. Sticky: it remains populated after a later successful reload, until restart.
rejectedarrayEntries the gateway rejected from the latest snapshot. Empty when everything loaded.

source fields:

FieldTypeDescription
typestringWhere configuration is read from: file or etcd.
connectedbooleanWhether the configuration store is reachable. Present only when type is etcd.
observed_revisionnumberStore revision of the latest observed snapshot. Present only when type is etcd.
source_hashstringSHA-256 hash of the latest observed snapshot. For a file source, this is the hash of the raw file bytes.
observed_atstringRFC 3339 UTC timestamp of the latest observation.

applied fields:

FieldTypeDescription
applied_revisionnumberStore revision the applied configuration reflects. Present only when source.type is etcd.
config_hashstringSHA-256 hash of the accepted, served configuration. Equal to source_hash when nothing was rejected.
apply_seqnumberCounter that increments each time the applied configuration changes. Unchanged content does not advance it.
applied_atstringRFC 3339 UTC timestamp of the last applied change.
resource_countsobjectServed resource count per kind, for example {"models": 2}.

last_reload and last_failure fields:

FieldTypeDescription
last_reload.successfulbooleanWhether the most recent load completed without rejections.
last_reload.atstringRFC 3339 UTC timestamp of the most recent load.
last_failure.atstringWhen the most recent failure occurred.
last_failure.last_error_kindstringFailure kind of the most recent failure.
last_failure.last_errorstringHuman-readable message of the most recent failure.

Each entry in rejected:

FieldTypeDescription
resource_kindstringPlural resource kind, such as models or provider_keys. Empty when the source entry could not be attributed to a kind.
resource_idstringResource ID. Empty when the source entry could not be parsed far enough to identify it.
last_error_kindstringFailure kind: bad_key, non_json, schema_failed, parse_failed, or unknown_kind.
last_errorstringHuman-readable error. Schema messages mask credential values.
first_seen_atstringWhen this rejection was first observed since the process started. Stable across repeated reloads of the same bad entry.
last_seen_atstringWhen 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"
ConditionStatusBody
No valid configuration applied yet503 Service Unavailableno configuration available
A valid configuration has been applied200 OKok

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 }
}
]
StatusMeaning
healthyThe model is in rotation.
cooldownRecent 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.
unhealthyRecent background model checks failed; routing avoids the model. last_check_status carries the HTTP status of the most recent check.
not_applicableThe 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.

MetricTypeLabelsDescription
aisix_config_last_reload_successfulgaugeNone1 when the most recent load completed without rejections, otherwise 0.
aisix_config_last_reload_success_timestamp_secondsgaugeNoneUnix timestamp of the most recent successful load.
aisix_config_reloads_totalcounterNoneConfiguration loads since the process started, counting boot loads, file reloads, and full synchronizations from the configuration store.
aisix_config_reload_failures_totalcounterreasonLoads 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_resourcesgaugekindCurrently rejected entries per resource kind. 0 after the offending entries are fixed.
aisix_config_hash_infogaugehashInfo-style series: exactly one live sample with value 1, whose hash label is the applied config_hash.
aisix_config_observed_revisiongaugeNoneStore revision of the latest observed snapshot. Emitted only for an etcd source.
aisix_config_applied_revisiongaugeNoneStore revision of the applied configuration. Emitted only for an etcd source.
aisix_config_source_connectedgaugeNone1 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