Errors — skyline-apiserver — branch stable/2026.2
Branch
stable/2026.2@4af72bfd4577— repository https://opendev.org/openstack/skyline-apiserver — analysed on 2026-10-28
skyline-apiserver defines no exception class of its own for the API (the inventory finds one, CommandException of the nginx generator, skyline_apiserver/cmd/generate_nginx.py:94). Every error a client sees is produced in one of three ways:
| Producer | Body | Where |
|---|---|---|
| authentication middleware | {"message": "Unauthorized: …"} | skyline_apiserver/main.py:110 |
raise HTTPException(status_code, detail) in handlers and client wrappers | {"detail": <string or object>} | FastAPI default handler |
| FastAPI request validation | 422 {"detail": [{"type", "loc", "msg", "input", "ctx"}…]} | FastAPI default handler |
| response validation or any uncaught exception | 500 with the plain-text body Internal Server Error | Starlette ServerErrorMiddleware |
There is no @app.exception_handler in the project: these are the framework defaults. All messages are in English, unlocalised. The observed bodies below come from _rewrite/outbound-calls_stable-2026.2.json.
Catalogue
Authentication (middleware)
| HTTP | Body | Situation | Raised at |
|---|---|---|---|
| 401 | {"message": "Unauthorized: Token not found"} | /api/v1/* call (outside the public list) with neither session cookie nor X-Auth-Token header | skyline_apiserver/main.py:109 |
| 401 | {"message": "Unauthorized: Token revoked"} | the JWT uuid is in revoked_token (after logout) | skyline_apiserver/main.py:125 |
| 401 | {"message": "Unauthorized: Token expired - Signature has expired."} | the JWT exp is past | skyline_apiserver/main.py:167 |
| 401 | {"message": "Unauthorized: Not enough segments"} (python-jose text) | the cookie is not a JWT, or bad signature (Signature verification failed.) | skyline_apiserver/main.py:172 |
| 401 | {"message": "Unauthorized: 401: <keystone text>"} | the Keystone token in the JWT or in X-Auth-Token is expired or revoked (GET /v3/auth/tokens fails); the HTTPException(401) of generate_profile is re-wrapped | skyline_apiserver/core/security.py:67, skyline_apiserver/main.py:172 |
| 401 | {"message": "Unauthorized: …"} | any other failure: Keystone unreachable, system account password wrong, identity endpoint missing (Endpoint not found, skyline_apiserver/client/utils.py:120), database error during the purge or the revocation check | skyline_apiserver/main.py:172 |
| 401 | {"detail": "Profile not found in request state"} | an endpoint that needs a profile is reached without one; cannot happen through the middleware except for a path it skips | skyline_apiserver/api/deps.py:52 |
Login, TOTP, WebSSO, project and region switch
| HTTP | detail | Situation | Raised at |
|---|---|---|---|
| 401 | Keystone's message, e.g. The request you have made requires authentication. (HTTP 401) | wrong user name, password or domain; user disabled | skyline_apiserver/api/v1/login.py:427 |
| 401 | The password is expired and needs to be changed for user: <user_id>. (HTTP 401) … [inferred text, from Keystone] | Keystone refuses an expired password; the console extracts <user_id> from this text | skyline_apiserver/api/v1/login.py:427 |
| 401 | {"totp_required": true, "receipt": "<receipt>"} | Keystone requires password and TOTP for this user (MissingAuthMethods with a receipt) | skyline_apiserver/api/v1/login.py:75 |
| 401 | An error occurred authenticating. Please try again later. | Keystone requires another combination of methods, or no receipt was given | skyline_apiserver/api/v1/login.py:79 |
| 401 | You are not authorized for any projects or domains. | the user has no role on any enabled project | skyline_apiserver/api/v1/login.py:303 |
| 401 | receipt_expired | /login/totp: Keystone says the receipt expired, or asks again for methods without a receipt header | skyline_apiserver/api/v1/login.py:119 |
| 401 | invalid_totp | /login/totp: Keystone answers 401 (wrong passcode) | skyline_apiserver/api/v1/login.py:131 |
| 401 | authentication_failed | /login/totp: any other error, or no token obtained | skyline_apiserver/api/v1/login.py:141, skyline_apiserver/api/v1/login.py:473 |
| 401 | text of the error | profile enrichment failed (projects, users, catalog, Neutron extensions) in /profile, /login, switches | skyline_apiserver/api/v1/login.py:376 |
| 401 | text of the error | /websso: token invalid, no project, enrichment failed | skyline_apiserver/api/v1/login.py:615 |
| 401 | Project not accessible | never in practice (dead check, 00 § 13) | skyline_apiserver/api/v1/login.py:713 |
| 401 | text of the error, e.g. Keystone's 401 message | /switch_project: Keystone refuses to re-scope (no role on the project, project disabled) | skyline_apiserver/api/v1/login.py:734 |
| 401 | Region not accessible | /switch_region: region not in the user's catalog, or catalog unreadable | skyline_apiserver/api/v1/login.py:772 |
| 401 | text of the error | /switch_region: no identity endpoint in that region, token validation failed | skyline_apiserver/api/v1/login.py:788 |
| 422 | validation list | missing username/password; passcode not 6 digits; bad X-Openstack-Request-Id | FastAPI |
Note that a Keystone outage during login is also reported as 401, with the connection error text.
Aggregated lists (/extension/*)
| HTTP | detail | Situation | Raised at |
|---|---|---|---|
| 403 | Not allowed to get servers for all projects. (and recycle servers, volumes, volume snapshots, ports) | all_projects=true without a system admin or reader role | skyline_apiserver/utils/roles.py:55, called at skyline_apiserver/api/v1/extension.py:131 |
| 403 | Not allowed to get compute services. | compute services without admin or reader role | skyline_apiserver/api/v1/extension.py:1069 |
| 400 | novaclient message, e.g. Invalid filter … (HTTP 400) | Nova rejects the server query (bad marker, bad sort key, bad ip regex) | skyline_apiserver/client/openstack/nova.py:52 |
| 401 | client message | the token was refused by the target service | skyline_apiserver/client/openstack/nova.py:57 and the other wrappers |
| 403 | novaclient message | Nova policy refuses (e.g. all_tenants for a reader) | skyline_apiserver/client/openstack/nova.py:62 |
| 500 | client message | any other error of Nova, Cinder, Glance, Neutron, Keystone (404 marker, 5xx, timeout after 30 s, connection refused) | skyline_apiserver/client/openstack/nova.py:67, skyline_apiserver/client/openstack/cinder.py:55, skyline_apiserver/client/openstack/glance.py:49, skyline_apiserver/client/openstack/neutron.py:47, skyline_apiserver/client/openstack/keystone.py:50 |
| 200 (empty list) | — | snapshot uuid not found, or in another project (Cinder 404 is caught) | skyline_apiserver/api/v1/extension.py:755 |
| 500 | Internal Server Error (text) | recycle bin not empty (bug, response model) | skyline_apiserver/api/v1/extension.py:405 |
| 500 | Internal Server Error (text) | a server, image or volume ID that is not a UUID v4 | skyline_apiserver/schemas/extension.py:206 |
| 422 | validation list | unknown sort_keys/status/device_owner enum value, limit <= 0 | FastAPI |
The client libraries' exceptions are not mapped by status code except Nova's 400/403: a Cinder 403 or a Neutron 404 becomes 500.
Catalog helpers, policies, Prometheus, settings
| HTTP | detail | Situation | Raised at |
|---|---|---|---|
| 500 | error text | /contrib/keystone_endpoints: system authentication or catalog failure, Neutron extensions unreachable | skyline_apiserver/api/v1/contrib.py:57 |
| 500 | Internal Server Error | /contrib/domains, /contrib/regions: Keystone failure (no try/except) | skyline_apiserver/api/v1/contrib.py:79, skyline_apiserver/api/v1/contrib.py:98 |
| 500 | Internal Server Error | /policies, /policies/check: re-scoping the user token fails (generate_session, not caught) | skyline_apiserver/client/utils.py:54 |
| 403 | the error text, e.g. 'foo' | /policies/check: unknown service prefix, or rule without : | skyline_apiserver/api/v1/policy.py:194 |
| (Prometheus status) | Prometheus body text | Prometheus answers non-200 (400 bad PromQL, 422, 503…) | skyline_apiserver/api/v1/prometheus.py:139 |
| 500 | connection error text | Prometheus unreachable | skyline_apiserver/utils/httpclient.py:36 |
| 404 | Not a valid setting key. | key not in setting.base_settings | skyline_apiserver/api/v1/setting.py:34 |
| 403 | Not allowed to update settings. / Not allowed to reset settings. | PUT/DELETE without a system admin role | skyline_apiserver/api/v1/setting.py:88, skyline_apiserver/api/v1/setting.py:148 |
| 500 | Internal Server Error | database failure in the settings handlers | skyline_apiserver/db/api.py:93 |
Exception → HTTP translation
- There is no central table. Each client wrapper of
skyline_apiserver/client/openstack/catcheskeystoneauth1.exceptions.http.Unauthorized→ 401, (Nova only)BadRequest→ 400 andForbidden→ 403, and everything else → 500 withstr(e)asdetail(skyline_apiserver/client/openstack/nova.py:52). - The middleware catches everything → 401 (
skyline_apiserver/main.py:172). This includesHTTPException(500)raised during profile building. - Login handlers catch everything → 401 (
skyline_apiserver/api/v1/login.py:427). - Uncaught exceptions in other handlers (e.g.
get_domains,generate_sessionin policies, pydanticValidationErroron the response) → 500 plain text. /logoutswallows every error (skyline_apiserver/api/v1/login.py:682).
Asynchronous errors
None: there is no background processing. The only deferred effect is the expiry of the session (cookie time_expired, JWT exp) and of the Keystone token, which surfaces as a 401 on the next call and makes the console go back to the login page.
Key log messages
Logging goes through loguru to <log_dir>/<log_file> (default /var/log/skyline/skyline.log, skyline_apiserver/main.py:47), level INFO, DEBUG when default.debug is true (skyline_apiserver/log/__init__.py:52). Standard logging records (uvicorn, httpx, alembic) are redirected to it (skyline_apiserver/log/__init__.py:80).
| Level | Message | Situation | Where |
|---|---|---|---|
| WARNING | TOTP receipt expired or invalid for user %s in domain %s: %s (placeholders not substituted by loguru) | receipt_expired | skyline_apiserver/api/v1/login.py:113 |
| WARNING | TOTP authentication failed for user %s in domain %s: %s | invalid_totp | skyline_apiserver/api/v1/login.py:125 |
| ERROR (+ traceback) | Unexpected error during TOTP authentication for user %s in domain %s | authentication_failed | skyline_apiserver/api/v1/login.py:136 |
| WARNING | An error occurred when calling <service> enforcer. | /policies: one service's rules failed as a whole | skyline_apiserver/api/v1/policy.py:136 |
| INFO | The <alias> resource could not be found. | profile building: a mapped Neutron extension is absent | skyline_apiserver/client/openstack/system.py:90 |
| DEBUG | Keystone token is invalid. No privilege to access system scope. / Keystone is not reachable. … | /policies: system re-scope refused | skyline_apiserver/api/v1/policy.py:117 |
| DEBUG | Not found volume snapshot with id '<id>': … / Volume snapshot with id '<id>' is in project … | snapshot uuid filter | skyline_apiserver/api/v1/extension.py:756 |
| DEBUG | Policy <rule> not registered. / Failed to load <service> rules. | policy evaluation | skyline_apiserver/policy/base.py:136 |
| DEBUG | exception text | errors swallowed by /logout | skyline_apiserver/api/v1/login.py:683 |
| DEBUG | Request path: <path> | every request | skyline_apiserver/main.py:78 |
The middleware's 401 conversions are not logged (skyline_apiserver/main.py:172): a Keystone outage only shows as a stream of 401 in the access log.
Source: reverse-spec-skyline-apiserver/02-errors_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.