OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Clients

python-octaviaclient — Errors

Errors — python-octaviaclient — branch stable/2026.2

Branch stable/2026.2 @ b37975ec8f2d (tag 3.15.0 + 2 commits) — repository https://opendev.org/openstack/python-octaviaclient — analysed on 2026-11-01

[observed] means reproduced against the local stub (scenarios in [_rewrite/defect-repro_stable-2026.2.json](_rewrite/defect-repro_stable-2026.2.json)). A stub shows how the client reacts to an answer, not whether a real service sends that answer.

1. Exit codes

ExitWhenSource
0the command returned normallycliff:cliff/command.py:196
1any exception raised by a command; the text goes to stderr through the loggercliff:cliff/app.py:435, cliff:cliff/app.py:462-467
2argparse rejected the arguments, or the command does not existcliff:cliff/app.py:428

**The command.Command return value is not a problem here**: cliff treats a returned value as the exit code (cliff:cliff/command.py:196), but none of the 38 command.Command classes returns one. This was checked by an AST walk, and all of them exit 0 on the typed stub [observed].

2. HTTP errors: correct_return_codes

All 73 API methods go through this decorator (octaviaclient/api/v2/octavia.py:26-62). keystoneauth raises an HttpError for any status of 400 or more; it carries response and request_id (keystoneauth:keystoneauth1/exceptions/http.py:81-82).

SituationException reaching the userTextSource
exception with response, JSON body with faultstringOctaviaClientException<faultstring> (HTTP <code>) (Request-ID: <id>)octaviaclient/api/v2/octavia.py:41-46, octaviaclient/api/exceptions.py:24-27
same, no faultstring; status in the tablesameForbidden (HTTP 403) (Request-ID: None) [observed]octaviaclient/api/v2/octavia.py:27-30
same, status not in the table (500, 502…)sameUnknown Error (HTTP 500) (Request-ID: None) [observed]octaviaclient/api/v2/octavia.py:37
body is not JSON, or JSON that is not an objectsamestatus table text [observed for a list body and for HTML]octaviaclient/api/v2/octavia.py:47-48
osc-lib ClientException with code != http_statussamethe code value as messageoctaviaclient/api/v2/octavia.py:49-53
anything else, including osc-lib NotFound(404, …)unchanged<value> not found (HTTP 404) from findoctaviaclient/api/v2/octavia.py:54-55, osc-lib:osc_lib/api/api.py:397-399

Status table: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not found, 409 Conflict, 413 Over Limit, 501 Not Implemented, 503 Service Unavailable. The request ID comes from the service's x-openstack-request-id header: denied (HTTP 403) (Request-ID: req-1234) [observed].

Consequence of the first row: the body {"faultcode", "faultstring", "debuginfo"} is what puts the service's text in front of the user. Octavia sends it (octavia:octavia/tests/functional/api/v2/test_load_balancer.py:139). A service using another shape shows canned text only.

**Status on GET of one resource**: find turns 404 and 400 into osc-lib NotFound (osc-lib:osc_lib/api/api.py:411-425), which triggers the show fallback [observed]. A 403 becomes denied (HTTP 403)… and stops there [observed].

3. Messages raised by the client

Message (template)ExceptionSituationRaised atObserved
Unable to locate {name} in {resource_name}CommandErrorlookup by ID and by name found nothingoctaviaclient/osc/v2/utils.py:102-103, octaviaclient/osc/v2/utils.py:196-197yes
{n} {resource_name} found with name or ID of {id}. Please try again with UUIDCommandErrorseveral resources share the nameoctaviaclient/osc/v2/utils.py:138-140yes
Additional VIPs must include a subnet-id.CommandError--additional-vip without subnet-idoctaviaclient/osc/v2/utils.py:215-216yes
text of ipaddress, for example 'abc' does not appear to be an IPv4 or IPv6 addressCommandErrorbad ip-address in --additional-vipoctaviaclient/osc/v2/utils.py:222-225yes
Missing required argument: Requires one of --vip-subnet-id, --vip-network-id or --vip-port-idCommandErrorloadbalancer create with no VIP optionoctaviaclient/osc/v2/load_balancer.py:41-43yes
Argument error: --vip-port-id can not be used with --vip-network-idCommandErrorboth optionsoctaviaclient/osc/v2/load_balancer.py:45-47yes, after both lookups
Missing argument: --redirect-pool, --redirect-url, --redirect-prefixCommandError--action without its target, on create and setoctaviaclient/osc/v2/validate.py:25-33yes for the first
Missing argument: --type {type_name} requires --key <key>CommandErrorCOOKIE or HEADER without --key, on create and setoctaviaclient/osc/v2/validate.py:40-43yes
Invalid input for field/attribute '{name}', Value: '{port}'. Value must be between 1 and 65535.InvalidValue--protocol-port out of range on listener and member createoctaviaclient/osc/v2/validate.py:51-56yes
Invalid input for field/attribute 'weight', Value: '{weight}'. Value must be between 0 and 256.InvalidValue--weight out of rangeoctaviaclient/osc/v2/validate.py:83-88yes
Argument hsts_max_age is required when using hsts_preload or hsts_include_subdomains arguments.InvalidValuelistener create onlyoctaviaclient/osc/v2/validate.py:67-69yes
Missing required argument. Requires at least one of: --healthmonitor, --listener, --loadbalancer, --member, --pool, --l7policy, --l7ruleCommandErrorquota set with no limitoctaviaclient/osc/v2/quota.py:108-110yes
The resource did not successfully reach ACTIVE status. (HTTP n/a) (Request-ID: None)OctaviaClientException--wait read erroroctaviaclient/osc/v2/utils.py:796-798yes
The resource could not be successfully deleted. (HTTP n/a) (Request-ID: None)OctaviaClientExceptiondelete --wait read error, or 300 s passedoctaviaclient/osc/v2/utils.py:816-818yes for error
<value> not found (HTTP 404)osc-lib NotFounddirect GET answered 404 or 400, with no fallback (amphora show, stats)osc-lib:osc_lib/api/api.py:397-399yes
No project with a name or ID of 'x' exists.CommandErrorproject lookup found nothingosc-lib:osc_lib/utils/__init__.py:290yes
public endpoint for load-balancer service in RegionOne region not foundkeystoneauthno such catalog entryoctaviaclient/osc/plugin.py:32-36yes

4. How a failure reaches the user

flowchart TD
  a[HTTP status 400 or more] --> b[keystoneauth HttpError]
  b --> c{find on 404 or 400?}
  c -->|yes| d[osc-lib NotFound, show falls back on lookup]
  c -->|no| e[correct_return_codes: OctaviaClientException]
  f[local validation] --> g[CommandError or InvalidValue]
  h[missing key, bad body, bad input] --> i[KeyError, TypeError, AttributeError, ValueError]
  d --> j[cliff logs the text on stderr, exit 1]
  e --> j
  g --> j
  i --> j

There is no asynchronous error beyond --wait, and no log message of the plugin's own. The package never uses its LOG (octaviaclient/osc/plugin.py:19).

5. Defects

Reproductions are in _rewrite/defect-repro_stable-2026.2.json, by scenario name. The stub chooses the answer, so "reproduced" means the client behaves this way on that answer. Whether a real service sends it is stated row by row.

#DefectWhat the user seesCodeEvidence
1The filter is dropped from page 2 onwards. params is replaced by the next link's queryextra, unfiltered rows, exit 0octaviaclient/api/v2/octavia.py:97-98; Octavia's link holds only limit, sort, marker: octavia:octavia/api/common/pagination.py:151-172pagination_filter_lost: ?name=x, then ?limit=1&marker=page1 [observed client]. Needs a full first page; the default is 1,000 (octavia:octavia/common/constants.py:755). Not run against Octavia
2**13 commands need a network catalog entry even with no VIP option**: loadbalancer create, list, show (by name), set, delete, failover, stats show, status show, and member create, list, show, set, deleteService 'network' is disabled because its configuration could not be loaded…, no request to Octaviamaps read client_manager.sdk_connection.network.* on every call: octaviaclient/osc/v2/utils.py:273, octaviaclient/osc/v2/utils.py:456field no_network_in_catalog: 13 fail, 69 exit 0 [observed]
3**--wait for ACTIVE never gives up**hangs until interruptedoctaviaclient/osc/v2/utils.py:789-794, osc-lib:osc_lib/utils/__init__.py:805-818wait_active_pending_forever: 6 polls in 12 s, then killed by the probe's own alarm [observed]. An unbounded loop was read in the code, not waited for
4Delete timeout and error share a message: after 300 s, or on errorThe resource could not be successfully deleted.octaviaclient/osc/v2/utils.py:815-818, osc-lib:osc_lib/utils/__init__.py:727wait_delete_error [observed]; the 300 s branch was read only
5**A 200 with a non-JSON body on a single GET**: requests.JSONDecodeError has response = None (requests:requests/exceptions.py:30), and the decorator reads e.response.status_code'NoneType' object has no attribute 'status_code'octaviaclient/api/v2/octavia.py:41-42show_html_200 [observed]. A proxy error page is a realistic source [inferred]
6A non-JSON body on list or create: BaseAPI returns the Response, the caller indexes it'Response' object is not subscriptable. The create was already sentosc-lib:osc_lib/api/api.py:180-183, octaviaclient/api/v2/octavia.py:92, octaviaclient/osc/v2/load_balancer.py:178list_html_200, create_empty_201 [observed]. set ignores the body and exits 0: set_html_200
7**{} on a single GET**list index out of rangeosc-lib:osc_lib/api/api.py:409show_uuid_empty_object [observed]
8A wrapper that is not the first key'int' object has no attribute 'get' with {"aaa":1,"loadbalancer":{…}}osc-lib:osc_lib/api/api.py:409-410show_wrapper_not_first [observed]
9A missing key gives a bare key name'loadbalancers', 'stats', 'tags', and so onoctaviaclient/api/v2/octavia.py:92, octaviaclient/osc/v2/load_balancer.py:592, octaviaclient/osc/v2/utils.py:827, octaviaclient/osc/v2/utils.py:839list_empty_object, stats_without_key, set_tag_no_tags_field, and the whole 200 probe [observed]
10**--wait on a response without the status field**'NoneType' object has no attribute 'lower', since _Munch answers None for any attributeoctaviaclient/osc/v2/utils.py:784-785, osc-lib:osc_lib/utils/__init__.py:807wait_active_no_status_field [observed]
11**create --wait fails after a successful create** when the parent list is emptylist index out of range, exit 1, listener exists. A retrying script will conflict or duplicateoctaviaclient/osc/v2/listener.py:253, octaviaclient/osc/v2/pool.py:176, octaviaclient/osc/v2/health_monitor.py:159create_wait_no_parent [observed]
12Bad user input gives a raw Python messagenot enough values to unpack (expected 2, got 1), too many values to unpack (expected 2), invalid literal for int() with base 10: 'abc'. A header value containing = cannot be expressedoctaviaclient/osc/v2/utils.py:762, octaviaclient/osc/v2/utils.py:234, octaviaclient/osc/v2/utils.py:566kv_no_equals_insert_headers, kv_two_equals_insert_headers, kv_no_equals_session_persistence, additional_vip_no_equals, hm_delay_not_int [observed]
13The monitor port check is dead: check_member_attrs reads member_port, while the map produces monitor_port. The unit test passes member_port, so it stays green--monitor-port 70000 is sent to the serviceoctaviaclient/osc/v2/validate.py:77-78, octaviaclient/osc/v2/utils.py:458, octaviaclient/tests/unit/osc/v2/test_validations.py:116member_monitor_port_out_of_range, member_set_monitor_port_out_of_range [observed]
14A test value is in production code: the project non-uuid skips the lookupquota show non-uuid calls GET /lbaas/quotas/non-uuidoctaviaclient/osc/v2/utils.py:173-179quota_non_uuid_literal [observed]
15Path values are not encodedprovider capability list a/b calls /providers/a/b/…; amphora show 'a?b=c' sends ?b=c as a queryoctaviaclient/api/v2/octavia.py:885-886, osc-lib:osc_lib/api/api.py:404name_with_slash_in_path, name_with_query_in_path [observed]
16**GET /lbaas/quotas/defaults is not a route of the service**: Octavia treats defaults as a project IDworks, returning defaults because no such project has a row; policy target is defaults, so a non-admin should get 403octaviaclient/api/constants.py:61, octavia:octavia/api/v2/controllers/quotas.py:37-41, octavia:octavia/api/v2/controllers/base.py:176-184read only; the 403 is [inferred], and reverse-spec-octavia/01-rest-api_stable-2026.2.md reaches the same conclusion. The stub answers this route

Lesser oddities [observed]:

  • --no-tag on create is accepted and has no effect.
  • set with no option sends an empty PUT, which may move a load balancer to PENDING_UPDATE on a real service [inferred].
  • listener set --hsts-preload skips the check that create applies; this is defensible, since the listener may already hold a maximum age.
  • Quota field spelling differs between set and unset.
  • A next link that repeats makes _list loop with no delay: 4,693 requests in 5 s in pagination_never_ends. Only a faulty service would cause it.
  • --os-loadbalancer-api-version validates nothing and is not sent.

Items 1 to 13 pass all unit tests, because commands use a mocked API (octaviaclient/tests/unit/osc/v2/test_load_balancer.py:36) and the API tests use well-formed bodies.

6. Timeouts and retries

  • The session is the one built by OSC; make_client adds no timeout (octaviaclient/osc/plugin.py:37-41). Unless the cloud sets api_timeout, a stuck service blocks the command [inferred; default read in python-openstackclient's report].
  • keystoneauth's connect_retries defaults to 0 (keystoneauth:keystoneauth1/session.py:408). The plugin sets no retry.
  • Connection failures carry no response, so they pass through the decorator unchanged (octaviaclient/api/v2/octavia.py:54-55) [inferred].

Source: reverse-spec-python-octaviaclient/02-errors_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.