Errors — octavia — branch stable/2026.2
Branch
stable/2026.2@2900ed67cac2— repository https://opendev.org/openstack/octavia — analysed on 2026-11-01
Every text below is exact unless a <placeholder> is shown. The (operation, status, message) combinations seen in the test run are in _rewrite/observed-errors_stable-2026.2.md, the probes in _rewrite/http-probes_stable-2026.2.json.
1. Body formats
| # | When | Body | Source |
|---|---|---|---|
| A | exception **inside a wsexpose handler** or its argument conversion (nearly everything) | {"faultcode": "Client", "faultstring": "<message>", "debuginfo": null}, Client for 4xx. Server for anything else: status = the exception's code if valid, else 500; faultstring = str(exception), including Python internals. debuginfo stays null (wsme.debug false: octavia/api/config.py:31-35) | WSME 0.13 wsme/api.py format_exception, wsmeext/pecan.py callfunction |
| B | webob HTTPException raised outside the handler: _lookup of pools and policies, limit/sort errors in the hook, unknown route, 405, 406 | {"code": 404, "title": "Bad Request", "description": "Pool <id> not found."}. title is the class's: APIException derives from HTTPClientError, so **every Octavia exception reported this way is titled Bad Request, whatever its status** (octavia/common/exceptions.py:63-69). Unknown path: {"code": 404, "description": "", "title": "Not Found"} (description is null above /v2) | Pecan 1.8 core.py, used because ContentTypeHook forces Accept: application/json |
| C | healthcheck routes, keystonemiddleware | text or HTML (404 Not Found\n\nThe resource could not be found.\n\n); 401 from auth_token ({"error": …}, not recorded) | oslo.middleware, keystonemiddleware |
utils.json_error_formatter builds an API-WG {"errors": [...]} body (octavia/api/common/utils.py:23-44), but it never reaches clients: the only exception using it is the 406 of ContentTypeHook (octavia/api/common/hooks.py:48-49), which Pecan re-renders in format B [probe accept_xml].
Which format applies is therefore a matter of where it is raised; the same exception class has two faces:
| Request | Format | Body |
|---|---|---|
GET /v2/lbaas/pools/{unknown} | A | {"debuginfo":null,"faultcode":"Client","faultstring":"Pool <id> not found."} |
GET /v2/lbaas/pools/{unknown}/members | B | {"code":404,"description":"Pool <id> not found.","title":"Bad Request"} |
GET …?marker=bogus | A | Supplied pagination marker 'bogus' is not valid. (raised in apply, under the handler) |
GET …?limit=abc | B | Supplied pagination limit 'abc' is not valid. (raised in the hook) |
Client expectations: python-octaviaclient and openstacksdk surface faultstring as the error message (openstacksdk:openstack/exceptions.py:200-201). x-openstack-request-id is on every response, errors included.
2. Exception → HTTP translation
There is no central table. An exception's HTTP status is its code class attribute: APIException subclasses declare one (octavia/common/exceptions.py:63), others default to 500 through WSME. Specific conversions:
| From | To | Where |
|---|---|---|
oslo_db DBDuplicateEntry on create | DuplicateListenerEntry, DuplicateMemberEntry, DuplicateHealthMonitor, IDAlreadyExists, RecordAlreadyExists | each _validate_create_*; octavia/api/v2/controllers/listener.py:367, octavia/api/v2/controllers/member.py:137, octavia/api/v2/controllers/health_monitor.py:170, octavia/api/v2/controllers/pool.py:164, octavia/api/v2/controllers/load_balancer.py:671, octavia/api/v2/controllers/flavors.py:102 |
DBReferenceError on create | InvalidOption(value, e.key) 400 | octavia/api/v2/controllers/pool.py:166, octavia/api/v2/controllers/member.py:141, octavia/api/v2/controllers/health_monitor.py:172 |
DBError | APIException 500 Something unknown went wrong; for listeners InvalidOption(protocol) 400; for HM post InvalidOption(type) 400 | octavia/api/v2/controllers/pool.py:169, octavia/api/v2/controllers/listener.py:371, octavia/api/v2/controllers/health_monitor.py:274 |
NoResultFound on LB row in test-and-set | not caught → 500 (the row was read earlier) [inferred] | octavia/db/repositories.py:809-812 |
DBDeadlock on quota row | ProjectBusyException 503 | octavia/db/repositories.py:620-623 |
| network driver errors in validators | InvalidSubresource 400 <Resource> <id> not found. for any failure, including Neutron being down | octavia/common/validate.py:333-340, octavia/common/validate.py:352-360 |
AllocateVIPException | status and message from orig_code, orig_msg if present | octavia/api/v2/controllers/load_balancer.py:360-368 |
| anything else | 500, faultcode: Server, text of the exception | WSME |
Provider exceptions (octavia/api/drivers/utils.py:38-84):
| octavia-lib exception raised by the driver | API exception | Status | faultstring |
|---|---|---|---|
Conflict | VIPAddressConflict | 409 | The VIP IP address is already in use: <user_fault_string> |
DriverError | ProviderDriverError | 500 | Provider '<p>' reports error: <user_fault_string> |
NotImplementedError (library or built-in) | ProviderNotImplementedError | 501 | Provider '<p>' does not support a requested action: <user_fault_string, default "This feature is not implemented by the provider."> |
UnsupportedOptionError | ProviderUnsupportedOptionError | 501 | Provider '<p>' does not support a requested option: <user_fault_string> |
| anything else | ProviderDriverError | 500 | Provider '<p>' reports error: <str(e)> |
The Go provider's driver API must map to these five classes (07 § 3).
3. Catalogue
Exceptions of octavia/common/exceptions.py reachable from the API scope (octavia/api/, octavia/common/validate.py, octavia/db/). Message templates use the Python % names.
| Exception | HTTP | Message template | Raised at (API scope) |
|---|---|---|---|
APIException | 500 | Something unknown went wrong | octavia/api/v2/controllers/l7rule.py:135, octavia/api/v2/controllers/member.py:145, octavia/api/v2/controllers/health_monitor.py:176, octavia/api/v2/controllers/l7policy.py:124, octavia/api/v2/controllers/pool.py:170 |
CertificateRetrievalException | 400 | Could not retrieve certificate: %(ref)s | octavia/api/drivers/utils.py:219, octavia/api/v2/controllers/base.py:262, octavia/api/v2/controllers/base.py:281 |
DisabledOption | 400 | The selected %(option)s is not allowed in this deployment: %(value)s | octavia/api/v2/controllers/load_balancer.py:452, octavia/api/v2/controllers/load_balancer.py:494, octavia/api/v2/controllers/health_monitor.py:228, octavia/api/v2/controllers/listener.py:224, octavia/api/v2/controllers/listener.py:229 |
DuplicateHealthMonitor | 409 | This pool already has a health monitor | octavia/api/v2/controllers/health_monitor.py:171 |
DuplicateListenerEntry | 409 | Another Listener on this Load Balancer is already using protocol %(protocol)s and protocol_port %(port)d | octavia/api/v2/controllers/listener.py:368, octavia/api/v2/controllers/listener.py:327 |
DuplicateMemberEntry | 409 | Another member on this pool is already using ip %(ip_address)s on protocol_port %(port)d | octavia/api/v2/controllers/member.py:138 |
DuplicatePoolEntry | 409 | This listener already has a default pool | octavia/api/v2/controllers/pool.py:290 |
IDAlreadyExists | 409 | Already an entity with that specified id. | octavia/api/v2/controllers/l7rule.py:130, octavia/api/v2/controllers/load_balancer.py:674, octavia/api/v2/controllers/flavor_profiles.py:122, octavia/api/v2/controllers/l7policy.py:119, octavia/api/v2/controllers/pool.py:165, octavia/api/v2/controllers/availability_zone_profiles.py:132 |
ImmutableObject | 409 | %(resource)s %(id)s is immutable and cannot be updated. | octavia/api/v2/controllers/l7rule.py:106, octavia/api/v2/controllers/l7rule.py:114, octavia/api/v2/controllers/member.py:119, octavia/api/v2/controllers/member.py:128, octavia/api/v2/controllers/health_monitor.py:106, octavia/api/v2/controllers/health_monitor.py:114, octavia/api/v2/controllers/l7policy.py:105, octavia/api/v2/controllers/pool.py:115 +5 |
InputFileError | 500 | Error with file %(file_name)s. Reason: %(reason)s | octavia/api/app.py:97 |
InvalidFilterArgument | 400 | One or more arguments are either duplicate or invalid | octavia/api/common/pagination.py:289 |
InvalidIPAddress | 400 | The IP Address %(ip_addr)s is invalid. | not raised in the API scope |
InvalidL7PolicyAction | 400 | Invalid L7 Policy action specified: %(action)s | octavia/common/validate.py:325, octavia/common/validate.py:283 |
InvalidL7PolicyArgs | 400 | Invalid L7 Policy arguments: %(msg)s | octavia/common/validate.py:287, octavia/common/validate.py:329, octavia/common/validate.py:268, octavia/common/validate.py:275, octavia/common/validate.py:280 |
InvalidL7Rule | 500 | Invalid L7 Rule: %(msg)s | octavia/common/validate.py:132, octavia/common/validate.py:247, octavia/common/validate.py:135, octavia/common/validate.py:146, octavia/common/validate.py:151, octavia/common/validate.py:162, octavia/common/validate.py:176, octavia/common/validate.py:194 +1 |
InvalidLimit | 400 | Supplied pagination limit '%(key)s' is not valid. | octavia/api/common/pagination.py:81 |
InvalidMarker | 400 | Supplied pagination marker '%(key)s' is not valid. | octavia/api/common/pagination.py:339 |
InvalidOption | 400 | %(value)s is not a valid option for %(option)s | octavia/api/v2/controllers/l7rule.py:132, octavia/api/v2/controllers/member.py:142, octavia/api/v2/controllers/health_monitor.py:126, octavia/api/v2/controllers/health_monitor.py:310, octavia/api/v2/controllers/health_monitor.py:312, octavia/api/v2/controllers/health_monitor.py:315, octavia/api/v2/controllers/health_monitor.py:123, octavia/api/v2/controllers/health_monitor.py:132 +26 |
InvalidRegex | 500 | Unable to parse regular expression: %(e)s | octavia/common/validate.py:123 |
InvalidSortDirection | 400 | Supplied sort direction '%(key)s' is not valid. | octavia/api/common/pagination.py:140, octavia/api/common/pagination.py:378 |
InvalidSortKey | 400 | Supplied sort key '%(key)s' is not valid. | octavia/api/common/pagination.py:97, octavia/api/common/pagination.py:329 |
InvalidString | 500 | Invalid characters in %(what)s | octavia/common/validate.py:97, octavia/common/validate.py:105, octavia/common/validate.py:114 |
InvalidSubresource | 400 | %(resource)s %(id)s not found. | octavia/common/validate.py:339, octavia/common/validate.py:358, octavia/common/validate.py:370, octavia/common/validate.py:391, octavia/common/validate.py:395, octavia/common/validate.py:408 |
InvalidURL | 500 | Not a valid URL: %(url)s | octavia/common/validate.py:54, octavia/common/validate.py:67 |
InvalidURLPath | 400 | Not a valid URLPath: %(url_path)s | octavia/common/validate.py:87, octavia/common/validate.py:89 |
L7RuleValidation | 400 | Error parsing L7Rule: %(error)s | octavia/api/v2/controllers/l7rule.py:207, octavia/api/v2/controllers/l7rule.py:160, octavia/api/v2/controllers/l7rule.py:244, octavia/db/prepare.py:125 |
LBPendingStateError | 409 | Invalid state %(state)s of loadbalancer resource %(id)s | octavia/api/v2/controllers/load_balancer.py:121, octavia/api/v2/controllers/load_balancer.py:131 |
ListenerNoChildren | 400 | Protocol %(protocol)s listeners cannot have child objects. | octavia/api/v2/controllers/l7policy.py:147, octavia/api/v2/controllers/pool.py:253, octavia/api/v2/controllers/listener.py:465, octavia/api/v2/controllers/listener.py:455, octavia/api/v2/controllers/listener.py:408, octavia/api/v2/controllers/listener.py:647 |
MemberSRIOVDisabled | 400 | The load balancer flavor does not allow SR-IOV member ports. | octavia/api/v2/controllers/member.py:265, octavia/api/v2/controllers/member.py:210 |
MissingAPIProjectID | 400 | Something unknown went wrong | octavia/api/v2/controllers/quotas.py:82, octavia/api/v2/controllers/quotas.py:106, octavia/api/v2/controllers/quotas.py:140 |
MissingArguments | 500 | Missing arguments. | octavia/db/repositories.py:1562 |
MissingCertSubject | 400 | No CN or DNSName(s) found in certificate. The certificate is invalid. | not raised in the API scope |
MissingProjectID | 500 | Missing project ID in request where one is required. | octavia/db/repositories.py:460 |
NotFound | 404 | %(resource)s %(id)s not found. | octavia/api/drivers/driver_agent/driver_updater.py:69, octavia/api/v2/controllers/amphora.py:230, octavia/api/v2/controllers/amphora.py:106, octavia/api/v2/controllers/load_balancer.py:69, octavia/api/v2/controllers/load_balancer.py:955, octavia/api/v2/controllers/load_balancer.py:986, octavia/api/v2/controllers/member.py:150, octavia/api/v2/controllers/member.py:189 +32 |
ObjectInUse | 409 | %(object)s %(id)s is in use and cannot be modified. | octavia/api/v2/controllers/flavor_profiles.py:148, octavia/api/v2/controllers/flavor_profiles.py:230, octavia/api/v2/controllers/flavors.py:167, octavia/api/v2/controllers/availability_zones.py:194, octavia/api/v2/controllers/availability_zone_profiles.py:162, octavia/api/v2/controllers/availability_zone_profiles.py:258 |
PolicyForbidden | 403 | Policy does not allow this request to be performed. | octavia/api/v2/controllers/base.py:217 |
PoolInUseByL7Policy | 409 | Pool %(id)s is in use by L7 policy %(l7policy_id)s | octavia/api/v2/controllers/pool.py:538 |
ProjectBusyException | 503 | Project busy. Unable to lock the project. Please try again. | octavia/db/repositories.py:623, octavia/db/repositories.py:733 |
ProviderDriverError | 500 | Provider '%(prov)s' reports error: %(user_msg)s | octavia/api/drivers/utils.py:61, octavia/api/drivers/utils.py:84 |
ProviderFlavorMismatchError | 400 | Flavor '%(flav)s' is not compatible with provider '%(prov)s' | octavia/api/v2/controllers/load_balancer.py:409 |
ProviderNotEnabled | 400 | Provider '%(prov)s' is not enabled. | octavia/api/drivers/driver_factory.py:40 |
ProviderNotFound | 501 | Provider '%(prov)s' was not found. | octavia/api/drivers/driver_factory.py:51 |
ProviderNotImplementedError | 501 | Provider '%(prov)s' does not support a requested action: %(user_msg)s | octavia/api/drivers/utils.py:74, octavia/api/v2/controllers/provider.py:93, octavia/api/v2/controllers/provider.py:145, octavia/api/v2/controllers/load_balancer.py:479 |
ProviderUnsupportedOptionError | 501 | Provider '%(prov)s' does not support a requested option: %(user_msg)s | octavia/api/drivers/utils.py:79 |
QuotaException | 403 | Quota has been met for resources: %(resource)s | octavia/api/v2/controllers/l7rule.py:171, octavia/api/v2/controllers/load_balancer.py:747, octavia/api/v2/controllers/load_balancer.py:772, octavia/api/v2/controllers/load_balancer.py:540, octavia/api/v2/controllers/member.py:201, octavia/api/v2/controllers/member.py:477, octavia/api/v2/controllers/health_monitor.py:254, octavia/api/v2/controllers/l7policy.py:168 +4 |
RecordAlreadyExists | 409 | A %(field)s of %(name)s already exists. | octavia/api/v2/controllers/flavors.py:104, octavia/api/v2/controllers/availability_zones.py:113 |
SingleCreateDetailsMissing | 400 | Missing details for %(type)s object: %(name)s | octavia/api/v2/controllers/load_balancer.py:784, octavia/api/v2/controllers/listener.py:477 |
TooManyL7RulesOnL7Policy | 409 | Too many rules on L7 policy %(id)s | octavia/api/v2/controllers/l7rule.py:122, octavia/db/prepare.py:119 |
UnreadablePKCS12 | 400 | The PKCS12 bundle is unreadable. Please check the PKCS12 bundle validity. In addition, make sure it does not require a pass phrase. Error: %(error)s | not raised in the API scope |
VIPAddressConflict | 409 | The VIP IP address is already in use: %(msg)s | octavia/api/drivers/utils.py:57 |
VIPValidationException | 400 | Validation failure: VIP must contain one of: %(objects)s. | octavia/api/v2/controllers/load_balancer.py:311 |
ValidationException | 400 | Validation failure: %(detail)s | octavia/api/drivers/utils.py:257, octavia/api/drivers/utils.py:314, octavia/api/v2/controllers/load_balancer.py:277, octavia/api/v2/controllers/load_balancer.py:297, octavia/api/v2/controllers/load_balancer.py:301, octavia/api/v2/controllers/load_balancer.py:305, octavia/api/v2/controllers/load_balancer.py:352, octavia/api/v2/controllers/load_balancer.py:509 +80 |
Messages for ValidationException (Validation failure: <detail>) are listed in the resource sheets of 01 § 4 with their source lines. Exceptions from octavia/network/base.py (NetworkException family) never reach the client directly except through § 2.
WSME-level errors (no Octavia class), from the probes and _rewrite/observed-errors_stable-2026.2.md:
| Situation | Status | faultstring |
|---|---|---|
| mandatory field absent | 400 | Invalid input for field/attribute <f>. Value: 'None'. Mandatory field missing. |
| type or range | 400 | Invalid input for field/attribute <f>. Value: '<v>'. <reason> |
| unknown attribute | 400 | Unknown attribute for argument <arg>[.<root>]: <names> (several: Unknown attributes for argument …: a, b, set order) |
| unknown query or form argument | 400 | Unknown argument: "<name>" |
| missing body or URL argument | 400 | Missing argument: "<name>" |
| wrong media type | 415 | Unknown mimetype: <type> |
| malformed JSON | 400 | Request is not in valid JSON format |
| no root object | 500 | 'UnsetType' object has no attribute '<attr>' or 'quota' |
| non-object body | 500 | 'list' object has no attribute 'keys' |
4. Asynchronous errors
These never appear in an HTTP status.
| Failure | Who sees it | Result |
|---|---|---|
provider reports provisioning_status: ERROR | GET of the object | object ERROR, parents as reported; a LB in ERROR can only be failed over or deleted |
| provider never reports | GET | stays PENDING_*; 409 on every further write to that LB. No API-side timeout |
status message with a record without id | the sender | {"status_code": 500, "fault_string": "'id'", "status_object": "members", "status_object_id": null}, stops at the first bad record, earlier records of the message are already committed (octavia/api/drivers/driver_agent/driver_updater.py:122-127, octavia/api/drivers/driver_agent/driver_updater.py:180-187; _rewrite/cases-driver-seam_stable-2026.2.json) |
| invalid status value | the sender | FK violation on the lookup table → same reply with the SQL text in fault_string |
| unknown id with status | nobody | UPDATE matches nothing → status 200 OK. With DELETED: NotFound swallowed → OK |
| statistics record missing a key | the sender | {"status_code": 500, "fault_string": "'bytes_out'", "stats_object": "listeners"} (octavia/api/drivers/driver_agent/driver_updater.py:218-222) |
| statistics for an unknown listener | nobody | inserted: listener_statistics has no FK to listener |
VIP deallocation failure on DELETED | sender (fault), LB stays as it was | octavia/api/drivers/driver_agent/driver_updater.py:99-101, wrapped at octavia/api/drivers/driver_agent/driver_updater.py:122-127 |
| quota decrement failure | log Failed to decrement %(name)s quota… | re-raised → fault to the sender, status not applied (octavia/api/drivers/driver_agent/driver_updater.py:81-87) |
5. Key log messages
| Level | Message | Situation | Where |
|---|---|---|---|
| ERROR | Server-side error: "<text>". Detail: <traceback> | every 500 through WSME | WSME |
| INFO | Sending create Load Balancer %s to provider %s (and the same for each op) | before each driver call | octavia/api/v2/controllers/load_balancer.py:664, others |
| INFO, EXCEPTION | Provider '%s' raised a conflict error…, … a driver error…, … a not implemented error…, … an unsupported option error…, … an unknown error… | § 2 | octavia/api/drivers/utils.py:55-83 |
| INFO | Invalid state %(state)s of loadbalancer resource %(id)s | LB immutable | octavia/api/v2/controllers/load_balancer.py:119 |
| INFO | Load Balancer %s is immutable. and … cannot be created or modified because the Load Balancer is in an immutable state | children | octavia/api/v2/controllers/listener.py:116, octavia/api/v2/controllers/pool.py:113 |
| INFO | Member batch update is a noop, rolling back and returning early. | § 01 4.4 | octavia/api/v2/controllers/member.py:465 |
| WARNING | Quota project lock timed out for project: %(proj)s | deadlock on quota | octavia/db/repositories.py:621 |
| WARNING, ERROR | Requested provider driver '%s' was not enabled…, Unable to load provider driver %s due to: %s | factory | octavia/api/drivers/driver_factory.py:37, octavia/api/drivers/driver_factory.py:47 |
| EXCEPTION | Cannot load driver '%s', will remove from service… | start-up | octavia/api/app.py:53 |
| ERROR | Could not delete VIP port %s of the failed load balancer creation, it may need to be deleted manually. | cleanup after failure | octavia/api/v2/controllers/load_balancer.py:384 |
Source: reverse-spec-octavia/02-errors_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.