Errors — ironic — branch stable/2026.2
Branch
stable/2026.2@39ce09ec3b0d— repository https://opendev.org/openstack/ironic — analysed on 2026-10-29
Ironic has one exception hierarchy, rooted at IronicException (ironic/common/exception.py:79): each class carries an HTTP code (500 by default) and a _msg_fmt template formatted with keyword arguments. 214 classes, 1 208 raise sites in the non-test code. The full catalogue below is generated from the imported classes (_rewrite/tools/ironic_errors.py, data in _rewrite/errors_stable-2026.2.json, every raise site listed there); the sections after it describe the situations that matter to a client or an operator.
1. Exception → HTTP translation
| Layer | Rule | Source |
|---|---|---|
| API handler | Every handler is wrapped by @method.expose: any exception is caught; if it has a code that is a known HTTP status, that status is used, otherwise 500. 4xx bodies carry faultcode: "Client" and faultstring = str(exc); 5xx bodies carry faultcode: "Server", the message, and the traceback only when [DEFAULT]/debug_tracebacks_in_api is true. | ironic/api/method.py:35, ironic/api/method.py:114 |
| Middleware | The body is then wrapped in {"error_message": "<inner JSON as a string>"} and Content-Type: application/json. | ironic/api/middleware/parsable_error.py:36 |
| RPC (oslo.messaging) | Conductor methods declare @messaging.expected_exceptions(...): those are re-raised on the API side with their class and code; any other exception becomes a RemoteError-like 500. NoExceptionTracebackHook strips the remote traceback from the message. | ironic/conductor/manager.py:125, ironic/api/hooks.py:127 |
| RPC (JSON-RPC) | The server returns {"error": {"code": <exc.code>, "message": str(exc), "data": {"class": "ironic.common.exception.X"}}}; the client re-creates the class when it is in an allowed namespace, otherwise raises a generic IronicException (500). | ironic/common/json_rpc/server.py:163, ironic/common/json_rpc/client.py:124 |
| Special codes set at the call site | NoValidHost (404 by class) is turned into 400 by the ramdisk endpoints (e.code = BAD_REQUEST), into 400 by node creation; TemporaryFailure (503) when no conductor is alive. | ironic/api/controllers/v1/ramdisk.py:197, ironic/conductor/rpcapi.py:278 |
webob errors | Raised directly by Pecan or by handlers (HTTPNotFound, HTTPMethodNotAllowed…) and by the version check (HTTPNotAcceptable, 406). | ironic/api/controllers/v1/__init__.py:155 |
What falls through to 500. Any exception without a 4xx code: NetworkError (Neutron failures during VIF attach: 45 raise sites), RedfishError (60), ImageRefValidationFailed (24), ConsoleContainerError (28), and programming errors. The version probe found two unexpected 500s (01 § 3.2).
Same exception, different statuses. NoValidHost (404 class) appears as 400 (lookup, heartbeat, node create); NotFound is used as a version gate (allow_* → 404 "Resource could not be found.") as well as for missing resources; InvalidState is 409 while InvalidStateRequested is 400, and the provision API chooses between NodeLocked (409) and InvalidStateRequested (400) for the same refused transition depending on whether the node is reserved (ironic/api/controllers/v1/node.py:1282). Clients that branch on the status (Nova retries 409 and 503 through openstacksdk, sdk:openstack/baremetal/v1/_common.py:22) depend on these choices.
2. Catalogue
<!-- GEN:errors-table -->
| Exception | Parent | HTTP | Message template | Raise sites | First raise sites |
|---|---|---|---|---|---|
ImageChecksumAlgorithmFailure (ironic/common/exception.py:1000) | InvalidImage | 500 | The requested image checksum algorithm cannot be loaded. | 3 | ironic/common/checksum_utils.py:105, ironic/common/checksum_utils.py:191, ironic/common/checksum_utils.py:321 |
ImageChecksumURLNotSupported (ironic/common/exception.py:1005) | InvalidImage | 500 | Use of remote checksum files is not supported. | 1 | ironic/common/checksum_utils.py:206 |
ImageChecksumFileReadFailure (ironic/common/exception.py:1010) | InvalidImage | 503 | Failed to read the file from local storage to perform a checksum operation. | 1 | ironic/common/checksum_utils.py:109 |
ParentNodeLocked (ironic/common/exception.py:1017) | Conflict | 409 | Node %(node)s parent_node %(parent)s is presently locked and we are unable to perform any action on it at this time. Please retry after the current operation… | 1 | ironic/conductor/utils.py:435 |
ChildNodeLocked (ironic/common/exception.py:1024) | Conflict | 409 | Node %(node)s child_node %(child)s is presently locked and we are unable to perform any action on it at this time. Please retry after the current operation i… | 1 | ironic/conductor/utils.py:468 |
InvalidMetricConfig (ironic/common/exception.py:1031) | Invalid | 400 | Unacceptable parameters. | 2 | ironic/common/metrics_utils.py:47, ironic/common/metrics_utils.py:76 |
MetricsNotSupported (ironic/common/exception.py:1037) | IronicException | 500 | Metrics action is not supported. You may need to adjust the [metrics] section in ironic.conf. | 1 | ironic/common/metrics.py:295 |
ServiceLookupFailure (ironic/common/exception.py:1042) | IronicException | 500 | Cannot find %(service)s service through multicast. | 0 | — |
ServiceRegistrationFailure (ironic/common/exception.py:1046) | IronicException | 500 | Cannot register %(service)s service: %(error)s | 3 | ironic/common/mdns.py:169, ironic/common/mdns.py:153, ironic/common/mdns.py:111 |
Unauthorized (ironic/common/exception.py:1050) | IronicException | 401 | An unknown exception occurred. | 1 | ironic/common/auth_basic.py:214 |
SecurityProxyNegotiationFailed (ironic/common/exception.py:1055) | IronicException | 500 | Failed to negotiate security type with server: %(reason)s | 6 | ironic/console/securityproxy/rfb.py:112, ironic/console/securityproxy/rfb.py:127, ironic/console/securityproxy/rfb.py:149 |
RFBAuthHandshakeFailed (ironic/common/exception.py:1059) | IronicException | 500 | Failed to complete auth handshake: %(reason)s | 1 | ironic/console/securityproxy/rfb.py:99 |
RFBAuthNoAvailableScheme (ironic/common/exception.py:1063) | IronicException | 500 | No matching auth scheme: allowed types: '%(allowed_types)s', desired types: '%(desired_types)s' | 1 | ironic/console/rfb/auths.py:49 |
ConsoleContainerError (ironic/common/exception.py:1069) | IronicException | 500 | Console container error with provider '%(provider)s', reason: %(reason)s | 28 | ironic/common/console_factory.py:61, ironic/console/container/systemd.py:191, ironic/console/container/systemd.py:54 |
ImageHostRateLimitFailure (ironic/common/exception.py:1074) | TemporaryFailure | 503 | The image registry has indicates the rate limit has been exceeded for url %(image_ref)s. Please try again later or consider using authentication and/or tryin… | 1 | ironic/common/oci_registry.py:143 |
ImageMatchFailure (ironic/common/exception.py:1080) | InvalidImage | 500 | The requested image lacks the required attributes to identify the file to select. | 0 | — |
OciImageNotSpecific (ironic/common/exception.py:1085) | InvalidImage | 500 | The requested image (%(image_ref)s) was not specific. Please supply a full URL mapping to the manifest to be utilized for the file download. | 2 | ironic/common/image_service.py:528, ironic/common/image_service.py:565 |
OciImageTagNotFound (ironic/common/exception.py:1091) | ImageNotFound | 404 | Image tag %(image_url)s could not be found, available tags are %(tags)s | 1 | ironic/common/oci_registry.py:730 |
ImageServiceAuthenticationRequired (ironic/common/exception.py:1096) | ImageUnacceptable | 500 | The requested image %(image_ref)s requires authentication which has not been provided. Unable to proceed. | 5 | ironic/common/oci_registry.py:445, ironic/common/oci_registry.py:592, ironic/common/oci_registry.py:645 |
InspectionRuleAlreadyExists (ironic/common/exception.py:1102) | Conflict | 409 | A rule with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:3441 |
InspectionRuleNotFound (ironic/common/exception.py:1107) | NotFound | 404 | Rule %(rule)s could not be found. | 3 | ironic/db/sqlalchemy/api.py:3470, ironic/db/sqlalchemy/api.py:3501, ironic/db/sqlalchemy/api.py:3457 |
InspectionRuleValidationFailure (ironic/common/exception.py:1112) | IronicException | 500 | Inspection rule validation failed. Reason: %(reason)s | 3 | ironic/common/inspection_rules/base.py:70, ironic/common/inspection_rules/base.py:113, ironic/common/inspection_rules/base.py:110 |
InspectionRuleExecutionFailure (ironic/common/exception.py:1117) | HardwareInspectionFailure | 500 | Inspection rule execution failed. Reason: %(reason)s | 4 | ironic/common/inspection_rules/actions.py:115, ironic/common/inspection_rules/operators.py:193, ironic/common/inspection_rules/operators.py:250 |
RuleActionExecutionFailure (ironic/common/exception.py:1122) | InspectionRuleExecutionFailure | 500 | Inspection rule action execution failed. Reason: %(reason)s | 17 | ironic/common/inspection_rules/actions.py:149, ironic/common/inspection_rules/actions.py:171, ironic/common/inspection_rules/actions.py:183 |
RuleConditionCheckFailure (ironic/common/exception.py:1128) | InspectionRuleExecutionFailure | 500 | Inspection rule condition check failed. Reason: %(reason)s | 1 | ironic/common/inspection_rules/operators.py:141 |
ConfigDriveRegenerationFailure (ironic/common/exception.py:1133) | IronicException | 500 | An unknown exception occurred. | 1 | ironic/conductor/configdrive_utils.py:438 |
TraitBasedNetworkingException (ironic/common/exception.py:1139) | IronicException | 500 | An unknown exception occurred. | 0 | — |
TBNComparatorPrefixMatchTypeMismatch (ironic/common/exception.py:1144) | TraitBasedNetworkingException | 500 | An unknown exception occurred. | 1 | ironic/common/trait_based_networking/base.py:91 |
TBNComparatorCollectionTypeMismatch (ironic/common/exception.py:1149) | TraitBasedNetworkingException | 500 | An unknown exception occurred. | 1 | ironic/common/trait_based_networking/base.py:112 |
TBNNoTraitsApplicableToNode (ironic/common/exception.py:1154) | TraitBasedNetworkingException | 500 | No Trait Based Networking traits were found which could apply to the node %(node)s. | 1 | ironic/drivers/modules/network/common.py:698 |
TBNNoPortMatchesFound (ironic/common/exception.py:1159) | TraitBasedNetworkingException | 500 | An unknown exception occurred. | 1 | ironic/drivers/modules/network/common.py:712 |
InvalidContent (ironic/common/exception.py:1164) | Invalid | 400 | Invalid or potentially malicious content has been provided to the conductor and the conductor will not proceed. | 5 | ironic/common/kickstart_utils.py:60, ironic/common/utils.py:1172, ironic/common/utils.py:1182 |
NotAuthorized (ironic/common/exception.py:128) | IronicException | 403 | Not authorized. | 11 | ironic/common/vnc.py:67, ironic/common/vnc.py:71, ironic/common/vnc.py:75 |
OperationNotPermitted (ironic/common/exception.py:133) | NotAuthorized | 403 | Operation not permitted. | 1 | ironic/api/controllers/v1/port.py:309 |
Invalid (ironic/common/exception.py:137) | IronicException | 400 | Unacceptable parameters. | 38 | ironic/common/neutron.py:1142, ironic/common/inspection_rules/actions.py:54, ironic/common/inspection_rules/operators.py:45 |
BadRequest (ironic/common/exception.py:137) | IronicException | 400 | Unacceptable parameters. | 9 | ironic/drivers/modules/inspect_utils.py:356, ironic/objects/deployment.py:115, ironic/objects/node.py:482 |
MalformedRequestURI (ironic/common/exception.py:142) | Invalid | 400 | Malformed request URI. | 20 | ironic/api/controllers/v1/port.py:606, ironic/api/controllers/v1/port.py:627, ironic/api/controllers/v1/port.py:749 |
Conflict (ironic/common/exception.py:146) | IronicException | 409 | Conflict. | 7 | ironic/drivers/modules/console_utils.py:173, ironic/drivers/modules/network/common.py:591, ironic/drivers/modules/network/common.py:631 |
TemporaryFailure (ironic/common/exception.py:151) | IronicException | 503 | Resource temporarily unavailable, please retry. | 8 | ironic/common/hash_ring.py:108, ironic/common/oci_registry.py:598, ironic/common/oci_registry.py:651 |
NotAcceptable (ironic/common/exception.py:156) | IronicException | 406 | Request not acceptable. | 58 | ironic/api/controllers/v1/port.py:400, ironic/api/controllers/v1/port.py:403, ironic/api/controllers/v1/port.py:406 |
InvalidState (ironic/common/exception.py:163) | Conflict | 409 | Invalid resource state. | 18 | ironic/common/async_steps.py:58, ironic/common/fsm.py:122, ironic/common/fsm.py:125 |
NodeAlreadyExists (ironic/common/exception.py:167) | Conflict | 409 | A node with UUID %(uuid)s already exists. | 2 | ironic/db/sqlalchemy/api.py:855, ironic/db/sqlalchemy/api.py:1013 |
MACAlreadyExists (ironic/common/exception.py:171) | Conflict | 409 | A port with MAC address %(mac)s already exists. | 2 | ironic/db/sqlalchemy/api.py:1169, ironic/db/sqlalchemy/api.py:1193 |
ChassisAlreadyExists (ironic/common/exception.py:175) | Conflict | 409 | A chassis with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:1394 |
PortAlreadyExists (ironic/common/exception.py:179) | Conflict | 409 | A port with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:1170 |
PortDuplicateName (ironic/common/exception.py:183) | Conflict | 409 | A port with name %(name)s already exists. | 1 | ironic/db/sqlalchemy/api.py:1191 |
PortgroupAlreadyExists (ironic/common/exception.py:187) | Conflict | 409 | A portgroup with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:1303 |
PortgroupDuplicateName (ironic/common/exception.py:191) | Conflict | 409 | A portgroup with name %(name)s already exists. | 2 | ironic/db/sqlalchemy/api.py:1299, ironic/db/sqlalchemy/api.py:1323 |
PortgroupMACAlreadyExists (ironic/common/exception.py:195) | Conflict | 409 | A portgroup with MAC address %(mac)s already exists. | 2 | ironic/db/sqlalchemy/api.py:1301, ironic/db/sqlalchemy/api.py:1325 |
InstanceAssociated (ironic/common/exception.py:199) | Conflict | 409 | Instance %(instance_uuid)s is already associated with a node, it cannot be associated with this other node %(node)s | 3 | ironic/db/sqlalchemy/api.py:852, ironic/db/sqlalchemy/api.py:2577, ironic/db/sqlalchemy/api.py:1015 |
DuplicateName (ironic/common/exception.py:204) | Conflict | 409 | A node with name %(name)s already exists. | 2 | ironic/db/sqlalchemy/api.py:850, ironic/db/sqlalchemy/api.py:1011 |
VolumeConnectorAlreadyExists (ironic/common/exception.py:208) | Conflict | 409 | A volume connector with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:1811 |
VolumeConnectorTypeAndIdAlreadyExists (ironic/common/exception.py:212) | Conflict | 409 | A volume connector with type %(type)s and connector ID %(connector_id)s already exists. | 2 | ironic/db/sqlalchemy/api.py:1831, ironic/db/sqlalchemy/api.py:1808 |
VolumeTargetAlreadyExists (ironic/common/exception.py:217) | Conflict | 409 | A volume target with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:1911 |
VolumeTargetBootIndexAlreadyExists (ironic/common/exception.py:221) | Conflict | 409 | A volume target with boot index '%(boot_index)s' for the same node already exists. | 2 | ironic/db/sqlalchemy/api.py:1930, ironic/db/sqlalchemy/api.py:1909 |
NodeInventoryAlreadyExists (ironic/common/exception.py:226) | Conflict | 409 | A node inventory with ID %(id)s already exists. | 0 | — |
VifAlreadyAttached (ironic/common/exception.py:230) | Conflict | 409 | Unable to attach VIF because VIF %(vif)s is already attached to Ironic %(object_type)s %(object_uuid)s | 1 | ironic/drivers/modules/network/common.py:73 |
NoFreePhysicalPorts (ironic/common/exception.py:235) | Invalid | 400 | Unable to attach VIF %(vif)s, not enough free physical ports. | 1 | ironic/drivers/modules/network/common.py:211 |
VifNotAttached (ironic/common/exception.py:240) | Invalid | 400 | Unable to detach VIF %(vif)s from node %(node)s because it is not attached to it. | 2 | ironic/drivers/modules/network/common.py:261, ironic/drivers/modules/network/common.py:479 |
InvalidUUID (ironic/common/exception.py:245) | Invalid | 400 | Expected a UUID but received %(uuid)s. | 3 | ironic/db/sqlalchemy/api.py:912, ironic/api/controllers/v1/volume_target.py:386, ironic/api/controllers/v1/volume_connector.py:349 |
InvalidUuidOrName (ironic/common/exception.py:249) | Invalid | 400 | Expected a logical name or UUID but received %(name)s. | 5 | ironic/api/controllers/v1/utils.py:613, ironic/api/controllers/v1/utils.py:652, ironic/api/controllers/v1/utils.py:691 |
InvalidName (ironic/common/exception.py:253) | Invalid | 400 | Expected a logical name but received %(name)s. | 0 | — |
InvalidConductorGroup (ironic/common/exception.py:257) | Invalid | 400 | Expected a conductor group but received %(group)s. | 2 | ironic/common/utils.py:564, ironic/common/utils.py:566 |
InvalidIdentity (ironic/common/exception.py:261) | Invalid | 400 | Expected a UUID or int but received %(identity)s. | 10 | ironic/objects/port.py:208, ironic/objects/volume_target.py:64, ironic/objects/portgroup.py:176 |
InvalidMAC (ironic/common/exception.py:265) | Invalid | 400 | Expected a MAC address but received %(mac)s. | 1 | ironic/common/utils.py:246 |
InvalidSwitchID (ironic/common/exception.py:269) | Invalid | 400 | Expected a MAC address or OpenFlow datapath ID but received %(switch_id)s. | 1 | ironic/api/controllers/v1/utils.py:203 |
InvalidDatapathID (ironic/common/exception.py:274) | Invalid | 400 | Expected an OpenFlow datapath ID but received %(datapath_id)s. | 1 | ironic/common/utils.py:272 |
InvalidStateRequested (ironic/common/exception.py:279) | Invalid | 400 | The requested action "%(action)s" can not be performed on node "%(node)s" while it is in state "%(state)s". | 20 | ironic/api/controllers/v1/node.py:884, ironic/api/controllers/v1/node.py:1294, ironic/api/controllers/v1/node.py:891 |
PatchError (ironic/common/exception.py:284) | Invalid | 400 | Couldn't apply patch '%(patch)s'. Reason: %(reason)s | 3 | ironic/api/controllers/v1/utils.py:488, ironic/api/controllers/v1/runbook.py:520, ironic/api/controllers/v1/inspection_rule.py:286 |
InstanceDeployFailure (ironic/common/exception.py:288) | IronicException | 500 | Failed to deploy instance: %(reason)s | 13 | ironic/drivers/modules/agent_base.py:308, ironic/drivers/modules/autodetect.py:78, ironic/drivers/modules/deploy_utils.py:235 |
ImageUnacceptable (ironic/common/exception.py:292) | IronicException | 500 | Image %(image_id)s is unacceptable: %(reason)s | 5 | ironic/common/pxe_utils.py:773, ironic/common/images.py:510, ironic/common/images.py:504 |
ImageConvertFailed (ironic/common/exception.py:296) | IronicException | 500 | Image %(image_id)s is unacceptable: %(reason)s | 1 | ironic/common/images.py:561 |
InvalidParameterValue (ironic/common/exception.py:302) | Invalid | 400 | %(err)s | 217 | ironic/drivers/utils.py:263, ironic/drivers/utils.py:98, ironic/drivers/utils.py:271 |
MissingParameterValue (ironic/common/exception.py:306) | InvalidParameterValue | 400 | %(err)s | 29 | ironic/drivers/utils.py:492, ironic/drivers/utils.py:92, ironic/drivers/modules/ipmitool.py:364 |
Duplicate (ironic/common/exception.py:310) | IronicException | 500 | Resource already exists. | 1 | ironic/common/fsm.py:45 |
NotFound (ironic/common/exception.py:314) | IronicException | 404 | Resource could not be found. | 26 | ironic/drivers/modules/inspect_utils.py:279, ironic/drivers/modules/inspect_utils.py:318, ironic/drivers/modules/inspect_utils.py:379 |
HTTPNotFound (ironic/common/exception.py:314) | IronicException | 404 | Resource could not be found. | 11 | ironic/api/controllers/v1/port.py:583, ironic/api/controllers/v1/portgroup.py:407, ironic/api/controllers/v1/allocation.py:589 |
DHCPLoadError (ironic/common/exception.py:319) | IronicException | 500 | Failed to load DHCP provider %(dhcp_provider_name)s, reason: %(reason)s | 1 | ironic/common/dhcp_factory.py:59 |
DriverNotFound (ironic/common/exception.py:328) | NotFound | 404 | Could not find the following driver(s) or hardware type(s): %(driver_name)s. | 4 | ironic/common/driver_factory.py:250, ironic/common/hash_ring.py:115, ironic/api/controllers/v1/driver.py:414 |
DriverNotFoundInEntrypoint (ironic/common/exception.py:333) | DriverNotFound | 404 | Could not find the following items in the '%(entrypoint)s' entrypoint: %(names)s. | 1 | ironic/common/driver_factory.py:383 |
InterfaceNotFoundInEntrypoint (ironic/common/exception.py:338) | InvalidParameterValue | 400 | Could not find the following interface in the '%(entrypoint)s' entrypoint: %(iface)s. Valid interfaces are %(valid)s. | 1 | ironic/common/driver_factory.py:97 |
IncompatibleInterface (ironic/common/exception.py:344) | InvalidParameterValue | 400 | %(interface_type)s interface implementation '%(interface_impl)s' is not supported by hardware type %(hardware_type)s. | 1 | ironic/common/driver_factory.py:111 |
NoValidDefaultForInterface (ironic/common/exception.py:350) | InvalidParameterValue | 400 | For%(node_info)s hardware type '%(driver)s', no default value found for %(interface_type)s interface could be determined. Please ensure the interfaces are en… | 2 | ironic/common/driver_factory.py:174, ironic/common/driver_factory.py:149 |
ImageNotFound (ironic/common/exception.py:359) | NotFound | 404 | Image %(image_id)s could not be found. | 5 | ironic/common/oci_registry.py:595, ironic/common/oci_registry.py:648, ironic/common/oci_registry.py:891 |
NoValidHost (ironic/common/exception.py:363) | NotFound | 404 | No valid host was found. Reason: %(reason)s | 1 | ironic/conductor/rpcapi.py:265 |
InstanceNotFound (ironic/common/exception.py:367) | NotFound | 404 | Instance %(instance)s could not be found. | 1 | ironic/db/sqlalchemy/api.py:921 |
InputFileError (ironic/common/exception.py:371) | IronicException | 500 | Error with file %(file_name)s. Reason: %(reason)s | 1 | ironic/api/app.py:130 |
NodeNotFound (ironic/common/exception.py:375) | NotFound | 404 | Node %(node)s could not be found. | 19 | ironic/db/sqlalchemy/api.py:725, ironic/db/sqlalchemy/api.py:745, ironic/db/sqlalchemy/api.py:873 |
SwitchNotFound (ironic/common/exception.py:379) | NotFound | 404 | Switch %(switch_id)s could not be found or is not supported by any configured switch driver. | 2 | ironic/drivers/modules/switch/generic_switch.py:122, ironic/networking/manager.py:262 |
DuplicateNodeOnLookup (ironic/common/exception.py:384) | NodeNotFound | 404 | Node %(node)s could not be found. | 1 | ironic/db/sqlalchemy/api.py:1753 |
PortgroupNotFound (ironic/common/exception.py:388) | NotFound | 404 | Portgroup %(portgroup)s could not be found. | 9 | ironic/db/sqlalchemy/api.py:1216, ironic/db/sqlalchemy/api.py:1226, ironic/db/sqlalchemy/api.py:1239 |
PortgroupNotEmpty (ironic/common/exception.py:392) | Invalid | 400 | Cannot complete the requested action because portgroup %(portgroup)s contains ports. | 2 | ironic/db/sqlalchemy/api.py:1346, ironic/conductor/manager.py:2871 |
NodeAssociated (ironic/common/exception.py:397) | InvalidState | 409 | Node %(node)s is associated with instance %(instance)s. | 3 | ironic/db/sqlalchemy/api.py:2554, ironic/conductor/manager.py:273, ironic/conductor/manager.py:2348 |
PortNotFound (ironic/common/exception.py:401) | NotFound | 404 | Port %(port)s could not be found. | 10 | ironic/common/inspection_rules/actions.py:345, ironic/common/inspection_rules/actions.py:373, ironic/common/inspection_rules/actions.py:410 |
FailedToUpdateDHCPOptOnPort (ironic/common/exception.py:405) | IronicException | 500 | Update DHCP options on port: %(port_id)s failed. | 3 | ironic/dhcp/neutron.py:128, ironic/dhcp/neutron.py:96, ironic/dhcp/neutron.py:143 |
FailedToCleanDHCPOpts (ironic/common/exception.py:409) | IronicException | 500 | Clean up DHCP options on node: %(node)s failed. | 0 | — |
FailedToGetIPAddressOnPort (ironic/common/exception.py:413) | IronicException | 500 | Retrieve IP address on port: %(port_id)s failed. | 2 | ironic/dhcp/neutron.py:205, ironic/dhcp/neutron.py:228 |
InvalidIPv4Address (ironic/common/exception.py:417) | IronicException | 500 | Invalid IPv4 address %(ip_address)s. | 1 | ironic/dhcp/neutron.py:197 |
InvalidIPAddress (ironic/common/exception.py:421) | IronicException | 500 | Invalid IP address %(ip_address)s. | 1 | ironic/dhcp/neutron.py:201 |
FailedToUpdateMacOnPort (ironic/common/exception.py:425) | IronicException | 500 | Update MAC address on port: %(port_id)s failed. | 1 | ironic/common/neutron.py:281 |
ChassisNotFound (ironic/common/exception.py:429) | NotFound | 404 | Chassis %(chassis)s could not be found. | 4 | ironic/db/sqlalchemy/api.py:1363, ironic/db/sqlalchemy/api.py:1374, ironic/db/sqlalchemy/api.py:1410 |
VolumeConnectorNotFound (ironic/common/exception.py:433) | NotFound | 404 | Volume connector %(connector)s could not be found. | 5 | ironic/db/sqlalchemy/api.py:1772, ironic/db/sqlalchemy/api.py:1782, ironic/db/sqlalchemy/api.py:1836 |
VolumeTargetNotFound (ironic/common/exception.py:437) | NotFound | 404 | Volume target %(target)s could not be found. | 5 | ironic/db/sqlalchemy/api.py:1863, ironic/db/sqlalchemy/api.py:1873, ironic/db/sqlalchemy/api.py:1933 |
NoDriversLoaded (ironic/common/exception.py:441) | IronicException | 500 | Conductor %(conductor)s cannot be started because no hardware types were loaded. | 1 | ironic/conductor/base_manager.py:253 |
ConductorNotFound (ironic/common/exception.py:446) | NotFound | 404 | Conductor %(conductor)s could not be found. | 4 | ironic/db/sqlalchemy/api.py:1535, ironic/db/sqlalchemy/api.py:1465, ironic/db/sqlalchemy/api.py:1476 |
ConductorAlreadyRegistered (ironic/common/exception.py:450) | IronicException | 500 | Conductor %(conductor)s already registered. | 1 | ironic/db/sqlalchemy/api.py:1438 |
ConductorHardwareInterfacesAlreadyRegistered (ironic/common/exception.py:454) | IronicException | 500 | Duplication detected for hardware_type, interface_type and interface combinations for this conductor while registering the row %(row)s | 0 | — |
PowerStateFailure (ironic/common/exception.py:460) | InvalidState | 409 | Failed to set node power state to %(pstate)s. | 8 | ironic/drivers/modules/agent_power.py:128, ironic/drivers/modules/agent_power.py:209, ironic/drivers/modules/agent_power.py:214 |
ExclusiveLockRequired (ironic/common/exception.py:464) | NotAuthorized | 403 | An exclusive lock is required, but the current context has a shared lock. | 1 | ironic/conductor/task_manager.py:150 |
NodeMaintenanceFailure (ironic/common/exception.py:469) | Invalid | 400 | Failed to toggle maintenance-mode flag for node %(node)s: %(reason)s | 0 | — |
NodeConsoleNotEnabled (ironic/common/exception.py:474) | Invalid | 400 | Console access is not enabled on node %(node)s | 1 | ironic/conductor/manager.py:2605 |
NodeInMaintenance (ironic/common/exception.py:478) | Invalid | 400 | The %(op)s operation can't be performed on node %(node)s because it's in maintenance mode. | 7 | ironic/api/controllers/v1/node.py:1274, ironic/conductor/deployments.py:51, ironic/conductor/manager.py:702 |
ChassisNotEmpty (ironic/common/exception.py:483) | Invalid | 400 | Cannot complete the requested action because chassis %(chassis)s contains nodes. | 1 | ironic/db/sqlalchemy/api.py:1421 |
IPMIFailure (ironic/common/exception.py:488) | IronicException | 500 | IPMI call failed: %(cmd)s. | 9 | ironic/drivers/modules/ipmitool.py:783, ironic/drivers/modules/ipmitool.py:849, ironic/drivers/modules/ipmitool.py:963 |
UnsupportedDriverExtension (ironic/common/exception.py:492) | Invalid | 400 | Driver %(driver)s does not support %(extension)s (disabled or not implemented). | 32 | ironic/drivers/base.py:855, ironic/drivers/base.py:866, ironic/drivers/base.py:1234 |
GlanceConnectionFailed (ironic/common/exception.py:497) | IronicException | 500 | Connection to glance endpoint %(endpoint)s failed: %(reason)s | 1 | ironic/common/glance_service/image_service.py:162 |
ImageNotAuthorized (ironic/common/exception.py:502) | NotAuthorized | 403 | Not authorized for image %(image_id)s. | 0 | — |
InvalidImageRef (ironic/common/exception.py:506) | InvalidParameterValue | 400 | Invalid image href %(image_href)s. | 5 | ironic/drivers/modules/agent.py:955, ironic/common/oci_registry.py:727, ironic/common/image_service.py:912 |
ImageRefValidationFailed (ironic/common/exception.py:510) | IronicException | 500 | Validation of image href %(image_href)s failed, reason: %(reason)s | 24 | ironic/common/oci_registry.py:837, ironic/common/oci_registry.py:854, ironic/common/image_service.py:246 |
ImageDownloadFailed (ironic/common/exception.py:515) | IronicException | 500 | Failed to download image %(image_href)s, reason: %(reason)s | 10 | ironic/drivers/modules/image_cache.py:240, ironic/drivers/modules/image_cache.py:259, ironic/common/oci_registry.py:900 |
KeystoneUnauthorized (ironic/common/exception.py:519) | IronicException | 500 | Not authorized in Keystone. | 1 | ironic/common/keystone.py:50 |
KeystoneFailure (ironic/common/exception.py:523) | IronicException | 500 | An unknown exception occurred. | 1 | ironic/common/keystone.py:57 |
CatalogNotFound (ironic/common/exception.py:527) | IronicException | 500 | Service type %(service_type)s with endpoint type %(endpoint_type)s not found in keystone service catalog. | 2 | ironic/common/keystone.py:129, ironic/common/keystone.py:47 |
ServiceUnavailable (ironic/common/exception.py:532) | IronicException | 500 | Connection failed | 3 | ironic/networking/rpcapi.py:90, ironic/conductor/rpcapi.py:50, ironic/conductor/rpcapi.py:220 |
InvalidEndpoint (ironic/common/exception.py:540) | IronicException | 500 | The provided endpoint is invalid | 0 | — |
CommunicationError (ironic/common/exception.py:544) | IronicException | 500 | Unable to communicate with the server. | 0 | — |
HTTPForbidden (ironic/common/exception.py:548) | NotAuthorized | 403 | Access was denied to the following resource: %(resource)s | 5 | ironic/common/policy.py:2172, ironic/api/controllers/v1/utils.py:1790, ironic/api/controllers/v1/ramdisk.py:161 |
ConfigNotFound (ironic/common/exception.py:556) | IronicException | 500 | Could not find config at %(path)s | 0 | — |
NodeLocked (ironic/common/exception.py:560) | Conflict | 409 | Node %(node)s is locked by host %(host)s, please retry after the current operation is completed. | 5 | ironic/db/sqlalchemy/api.py:777, ironic/db/sqlalchemy/api.py:785, ironic/db/sqlalchemy/api.py:811 |
NodeNotLocked (ironic/common/exception.py:565) | Invalid | 400 | Node %(node)s found not to be locked on release | 1 | ironic/db/sqlalchemy/api.py:809 |
NoFreeConductorWorker (ironic/common/exception.py:569) | TemporaryFailure | 503 | Requested action cannot be performed due to lack of free conductor workers. | 2 | ironic/conductor/base_manager.py:578, ironic/conductor/base_manager.py:571 |
VendorPassthruException (ironic/common/exception.py:575) | IronicException | 500 | An unknown exception occurred. | 1 | ironic/drivers/base.py:1076 |
ConfigInvalid (ironic/common/exception.py:579) | IronicException | 500 | Invalid configuration file. %(error_msg)s | 12 | ironic/networking/manager.py:177, ironic/networking/switch_drivers/driver_factory.py:87, ironic/networking/switch_drivers/driver_factory.py:76 |
DriverLoadError (ironic/common/exception.py:583) | IronicException | 500 | Driver, hardware type or interface %(driver)s could not be loaded. Reason: %(reason)s. | 5 | ironic/drivers/modules/ipmitool.py:1024, ironic/common/driver_factory.py:357, ironic/common/driver_factory.py:490 |
DriverOperationError (ironic/common/exception.py:588) | IronicException | 500 | Runtime driver %(driver)s failure. Reason: %(reason)s. | 0 | — |
ConsoleError (ironic/common/exception.py:592) | IronicException | 500 | An unknown exception occurred. | 2 | ironic/drivers/modules/console_utils.py:73, ironic/drivers/modules/console_utils.py:132 |
NoConsolePid (ironic/common/exception.py:596) | ConsoleError | 500 | Could not find pid in pid file %(pid_path)s | 1 | ironic/drivers/modules/console_utils.py:94 |
ConsoleSubprocessFailed (ironic/common/exception.py:600) | ConsoleError | 500 | Console subprocess failed to start. %(error)s | 2 | ironic/drivers/modules/console_utils.py:380, ironic/drivers/modules/console_utils.py:337 |
PasswordFileFailedToCreate (ironic/common/exception.py:604) | IronicException | 500 | Failed to create the password file. %(error)s | 2 | ironic/drivers/modules/ipmitool.py:302, ironic/drivers/modules/console_utils.py:151 |
DracOperationError (ironic/common/exception.py:608) | DriverOperationError | 500 | DRAC operation failed. Reason: %(error)s | 0 | — |
FailedToGetSensorData (ironic/common/exception.py:612) | IronicException | 500 | Failed to get sensor data for node %(node)s. Error: %(error)s | 1 | ironic/drivers/modules/ipmitool.py:1424 |
FailedToParseSensorData (ironic/common/exception.py:617) | IronicException | 500 | Failed to parse sensor data for node %(node)s. Error: %(error)s | 2 | ironic/drivers/modules/ipmitool.py:887, ironic/drivers/modules/ipmitool.py:927 |
InsufficientDiskSpace (ironic/common/exception.py:622) | IronicException | 500 | Disk volume where '%(path)s' is located doesn't have enough disk space. Required %(required)d MiB, only %(actual)d MiB available space present. | 2 | ironic/drivers/modules/image_cache.py:501, ironic/common/utils.py:421 |
ImageCreationFailed (ironic/common/exception.py:628) | IronicException | 500 | Creating %(image_type)s image failed: %(error)s | 11 | ironic/common/images.py:901, ironic/common/images.py:106, ironic/common/images.py:879 |
SwiftOperationError (ironic/common/exception.py:632) | IronicException | 500 | Swift operation '%(operation)s' failed: %(error)s | 6 | ironic/common/swift.py:65, ironic/common/swift.py:75, ironic/common/swift.py:94 |
SwiftObjectNotFoundError (ironic/common/exception.py:636) | SwiftOperationError | 500 | Swift object %(obj)s from container %(container)s not found. Operation '%(operation)s' failed. | 3 | ironic/drivers/modules/inspect_utils.py:225, ironic/drivers/modules/inspect_utils.py:233, ironic/common/swift.py:172 |
SNMPFailure (ironic/common/exception.py:641) | DriverOperationError | 500 | SNMP operation '%(operation)s' failed: %(error)s | 0 | — |
FileSystemNotSupported (ironic/common/exception.py:645) | IronicException | 500 | Failed to create a file system. File system %(fs)s is not supported. | 1 | ironic/common/utils.py:808 |
HardwareInspectionFailure (ironic/common/exception.py:650) | IronicException | 500 | Failed to inspect hardware. Reason: %(error)s | 11 | ironic/drivers/modules/inspect_utils.py:536, ironic/drivers/modules/inspect_utils.py:615, ironic/drivers/modules/inspect_utils.py:571 |
NodeCleaningFailure (ironic/common/exception.py:654) | IronicException | 500 | Failed to clean node %(node)s: %(reason)s | 7 | ironic/drivers/modules/ansible/deploy.py:332, ironic/drivers/modules/ansible/deploy.py:337, ironic/drivers/modules/ansible/deploy.py:354 |
NodeServicingFailure (ironic/common/exception.py:658) | IronicException | 500 | Failed to service node %(node)s: %(reason)s | 0 | — |
PathNotFound (ironic/common/exception.py:662) | IronicException | 500 | Path %(dir)s does not exist. | 1 | ironic/common/utils.py:390 |
DirectoryNotWritable (ironic/common/exception.py:666) | IronicException | 500 | Directory %(dir)s is not writable. | 1 | ironic/common/utils.py:405 |
ImageUploadFailed (ironic/common/exception.py:670) | IronicException | 500 | Failed to upload %(image_name)s image to web server %(web_server)s, reason: %(reason)s | 0 | — |
NodeTagNotFound (ironic/common/exception.py:675) | IronicException | 500 | Node %(node_id)s doesn't have a tag '%(tag)s' | 1 | ironic/db/sqlalchemy/api.py:1727 |
NetworkError (ironic/common/exception.py:679) | IronicException | 500 | Network operation failure. | 45 | ironic/drivers/modules/network/neutron.py:174, ironic/drivers/modules/network/neutron.py:189, ironic/drivers/modules/network/flat.py:85 |
IncompleteLookup (ironic/common/exception.py:683) | Invalid | 400 | At least one of 'addresses' and 'node_uuid' parameters is required | 1 | ironic/api/controllers/v1/ramdisk.py:171 |
NotificationSchemaObjectError (ironic/common/exception.py:688) | IronicException | 500 | Expected object %(obj)s when populating notification payload but got object %(source)s | 1 | ironic/objects/notification.py:156 |
NotificationSchemaKeyError (ironic/common/exception.py:693) | IronicException | 500 | Object %(obj)s doesn't have the field "%(field)s" required for populating notification schema key "%(key)s" | 2 | ironic/objects/notification.py:170, ironic/objects/notification.py:174 |
NotificationPayloadError (ironic/common/exception.py:699) | IronicException | 500 | Payload not populated when trying to send notification "%(class_name)s" | 1 | ironic/objects/notification.py:112 |
StorageError (ironic/common/exception.py:704) | IronicException | 500 | Storage operation failure. | 11 | ironic/drivers/modules/deploy_utils.py:1777, ironic/drivers/modules/deploy_utils.py:1782, ironic/drivers/modules/storage/cinder.py:263 |
RedfishError (ironic/common/exception.py:708) | DriverOperationError | 500 | Redfish exception occurred. Error: %(error)s | 60 | ironic/drivers/modules/redfish/firmware_utils.py:206, ironic/drivers/modules/redfish/firmware_utils.py:200, ironic/drivers/modules/redfish/firmware_utils.py:252 |
RedfishConnectionError (ironic/common/exception.py:712) | RedfishError | 500 | Redfish connection failed for node %(node)s: %(error)s | 2 | ironic/drivers/modules/redfish/utils.py:555, ironic/drivers/modules/redfish/utils.py:636 |
PortgroupPhysnetInconsistent (ironic/common/exception.py:716) | IronicException | 500 | Port group %(portgroup)s has member ports with inconsistent physical networks (%(physical_networks)s). All ports in a port group must have the same physical … | 1 | ironic/common/network.py:147 |
VifInvalidForAttach (ironic/common/exception.py:722) | Conflict | 409 | Unable to attach VIF %(vif)s to node %(node)s. Reason: %(reason)s | 0 | — |
AgentAPIError (ironic/common/exception.py:727) | IronicException | 500 | Agent API for node %(node)s returned HTTP status code %(status)s with error: %(error)s | 2 | ironic/drivers/modules/agent_client.py:158, ironic/drivers/modules/agent_client.py:303 |
NodeTraitNotFound (ironic/common/exception.py:732) | NotFound | 404 | Node %(node_id)s doesn't have a trait '%(trait)s' | 2 | ironic/db/sqlalchemy/api.py:2315, ironic/api/controllers/v1/node.py:1624 |
InstanceRescueFailure (ironic/common/exception.py:736) | IronicException | 500 | Failed to rescue instance %(instance)s for node %(node)s: %(reason)s | 4 | ironic/drivers/modules/agent_base.py:729, ironic/drivers/modules/agent_base.py:719, ironic/drivers/modules/agent_client.py:875 |
InstanceUnrescueFailure (ironic/common/exception.py:741) | IronicException | 500 | Failed to unrescue instance %(instance)s for node %(node)s: %(reason)s | 1 | ironic/conductor/manager.py:818 |
BIOSSettingAlreadyExists (ironic/common/exception.py:746) | Conflict | 409 | A BIOS setting %(name)s for node %(node)s already exists. | 1 | ironic/db/sqlalchemy/api.py:2350 |
BIOSSettingNotFound (ironic/common/exception.py:750) | NotFound | 404 | Node %(node)s doesn't have a BIOS setting '%(name)s' | 3 | ironic/db/sqlalchemy/api.py:2382, ironic/db/sqlalchemy/api.py:2409, ironic/api/controllers/v1/bios.py:116 |
BIOSSettingListNotFound (ironic/common/exception.py:754) | NotFound | 404 | Node %(node)s doesn't have BIOS settings '%(names)s' | 1 | ironic/db/sqlalchemy/api.py:2398 |
DatabaseVersionTooOld (ironic/common/exception.py:758) | IronicException | 500 | Database version is too old | 1 | ironic/db/sqlalchemy/api.py:1999 |
AgentConnectionFailed (ironic/common/exception.py:762) | IronicException | 500 | Connection to agent failed: %(reason)s | 3 | ironic/drivers/modules/agent_client.py:120, ironic/drivers/modules/agent_client.py:442, ironic/drivers/modules/agent_client.py:370 |
AgentCommandTimeout (ironic/common/exception.py:766) | IronicException | 500 | Timeout executing command %(command)s on node %(node)s | 3 | ironic/drivers/modules/agent_client.py:181, ironic/drivers/modules/agent_client.py:186, ironic/drivers/modules/agent_client.py:947 |
NodeProtected (ironic/common/exception.py:770) | HTTPForbidden | 403 | Node %(node)s is protected and cannot be undeployed, rebuilt or deleted | 3 | ironic/conductor/deployments.py:55, ironic/conductor/manager.py:1089, ironic/conductor/manager.py:2352 |
AllocationNotFound (ironic/common/exception.py:775) | NotFound | 404 | Allocation %(allocation)s could not be found. | 9 | ironic/db/sqlalchemy/api.py:2569, ironic/db/sqlalchemy/api.py:2612, ironic/db/sqlalchemy/api.py:2433 |
AllocationDuplicateName (ironic/common/exception.py:779) | Conflict | 409 | An allocation with name %(name)s already exists. | 2 | ironic/db/sqlalchemy/api.py:2572, ironic/db/sqlalchemy/api.py:2512 |
AllocationAlreadyExists (ironic/common/exception.py:783) | Conflict | 409 | An allocation with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:2515 |
AllocationFailed (ironic/common/exception.py:787) | IronicException | 500 | Failed to process allocation %(uuid)s: %(error)s. | 4 | ironic/conductor/allocations.py:252, ironic/conductor/allocations.py:128, ironic/conductor/allocations.py:137 |
IronicException (ironic/common/exception.py:79) | Exception | 500 | An unknown exception occurred. | 13 | ironic/drivers/modules/agent_client.py:864, ironic/drivers/modules/agent_client.py:251, ironic/drivers/modules/agent_client.py:266 |
DeployTemplateDuplicateName (ironic/common/exception.py:791) | Conflict | 409 | A deploy template with name %(name)s already exists. | 2 | ironic/db/sqlalchemy/api.py:2750, ironic/db/sqlalchemy/api.py:2668 |
DeployTemplateAlreadyExists (ironic/common/exception.py:795) | Conflict | 409 | A deploy template with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:2670 |
DeployTemplateNotFound (ironic/common/exception.py:799) | NotFound | 404 | Deploy template %(template)s could not be found. | 3 | ironic/db/sqlalchemy/api.py:2755, ironic/db/sqlalchemy/api.py:2766, ironic/db/sqlalchemy/api.py:2777 |
InvalidDeployTemplate (ironic/common/exception.py:803) | Invalid | 400 | Deploy template invalid: %(err)s. | 1 | ironic/api/controllers/v1/utils.py:1705 |
RunbookDuplicateName (ironic/common/exception.py:807) | Conflict | 409 | A runbook with name %(name)s already exists. | 2 | ironic/db/sqlalchemy/api.py:2932, ironic/db/sqlalchemy/api.py:2846 |
RunbookAlreadyExists (ironic/common/exception.py:811) | Conflict | 409 | A runbook with UUID %(uuid)s already exists. | 1 | ironic/db/sqlalchemy/api.py:2849 |
RunbookNotFound (ironic/common/exception.py:815) | NotFound | 404 | Runbook %(runbook)s could not be found. | 5 | ironic/db/sqlalchemy/api.py:2997, ironic/db/sqlalchemy/api.py:2937, ironic/db/sqlalchemy/api.py:2950 |
RunbookTraitNotFound (ironic/common/exception.py:819) | NotFound | 404 | Runbook %(runbook_id)s doesn't have a trait '%(trait)s' | 1 | ironic/db/sqlalchemy/api.py:3065 |
InvalidRunbook (ironic/common/exception.py:823) | Invalid | 400 | Runbook invalid: %(err)s. | 0 | — |
InvalidKickstartTemplate (ironic/common/exception.py:827) | Invalid | 400 | The kickstart template is missing required variables | 2 | ironic/common/pxe_utils.py:1187, ironic/common/pxe_utils.py:1177 |
InvalidKickstartFile (ironic/common/exception.py:831) | Invalid | 400 | The kickstart file is not valid. | 1 | ironic/common/pxe_utils.py:1217 |
ClientSideError (ironic/common/exception.py:835) | RuntimeError | — | — | 34 | ironic/api/controllers/v1/port.py:817, ironic/api/controllers/v1/portgroup.py:493, ironic/api/controllers/v1/portgroup.py:568 |
NodeIsRetired (ironic/common/exception.py:852) | Invalid | 400 | The %(op)s operation can't be performed on node %(node)s because it is retired. | 1 | ironic/conductor/manager.py:1484 |
NoFreeIPMITerminalPorts (ironic/common/exception.py:857) | TemporaryFailure | 503 | Unable to allocate a free port on host %(host)s for IPMI terminal, not enough free ports. | 1 | ironic/drivers/modules/console_utils.py:197 |
InvalidInput (ironic/common/exception.py:862) | ClientSideError | — | — | 2 | ironic/api/controllers/v1/volume_target.py:317, ironic/api/controllers/v1/volume_connector.py:275 |
UnknownArgument (ironic/common/exception.py:880) | ClientSideError | — | — | 0 | — |
UnknownAttribute (ironic/common/exception.py:893) | ClientSideError | — | — | 0 | — |
AgentInProgress (ironic/common/exception.py:921) | IronicException | 500 | Node %(node)s command "%(command)s" failed. Agent is presently executing a command. Error %(error)s | 1 | ironic/drivers/modules/agent_client.py:300 |
InsufficientMemory (ironic/common/exception.py:926) | IronicException | 500 | Available memory at %(free)s, Insufficient as %(required)s is required to proceed at this time. | 1 | ironic/common/utils.py:650 |
NodeHistoryNotFound (ironic/common/exception.py:931) | NotFound | 404 | Node history record %(history)s could not be found. | 3 | ironic/db/sqlalchemy/api.py:3097, ironic/db/sqlalchemy/api.py:3106, ironic/db/sqlalchemy/api.py:3116 |
NodeInventoryNotFound (ironic/common/exception.py:935) | NotFound | 404 | Node inventory record for node %(node)s could not be found. | 4 | ironic/drivers/modules/inspect_utils.py:188, ironic/drivers/modules/inspect_utils.py:186, ironic/db/sqlalchemy/api.py:3277 |
IncorrectConfiguration (ironic/common/exception.py:939) | IronicException | 500 | Supplied configuration is incorrect and must be fixed. Error: %(error)s | 5 | ironic/common/pxe_utils.py:1393, ironic/common/pxe_utils.py:1400, ironic/common/pxe_utils.py:1414 |
NodeVerifyFailure (ironic/common/exception.py:944) | IronicException | 500 | Failed to verify node %(node)s: %(reason)s | 1 | ironic/drivers/modules/redfish/management.py:689 |
ConcurrentActionLimit (ironic/common/exception.py:948) | TemporaryFailure | 503 | Unable to process request at this time. The concurrent action limit for %(task_type)s has been reached. Please contact your administrator and try again later. | 2 | ironic/conductor/manager.py:4230, ironic/conductor/manager.py:4243 |
SwiftObjectStillExists (ironic/common/exception.py:958) | IronicException | 500 | Clean up failed for swift object %(obj)s during deletion of node %(node)s. | 2 | ironic/drivers/modules/inspect_utils.py:116, ironic/drivers/modules/inspect_utils.py:126 |
FirmwareComponentAlreadyExists (ironic/common/exception.py:963) | Conflict | 409 | A Firmware component %(name)s for node %(node)s already exists. | 1 | ironic/db/sqlalchemy/api.py:3336 |
FirmwareComponentNotFound (ironic/common/exception.py:968) | NotFound | 404 | Node %(node)s doesn't have Firmware component %(name)s | 2 | ironic/db/sqlalchemy/api.py:3366, ironic/db/sqlalchemy/api.py:3391 |
InvalidNodeInventory (ironic/common/exception.py:972) | Invalid | 400 | Inventory for node %(node)s is invalid: %(reason)s | 5 | ironic/drivers/modules/inspector/hooks/memory.py:40, ironic/drivers/modules/inspector/hooks/validate_interfaces.py:52, ironic/drivers/modules/inspector/hooks/validate_interfaces.py:105 |
UnsupportedHardwareFeature (ironic/common/exception.py:976) | Invalid | 400 | Node %(node)s hardware does not support feature %(feature)s, which is required based upon the requested configuration. | 2 | ironic/drivers/modules/ipmitool.py:1124, ironic/drivers/modules/redfish/boot.py:1437 |
BootModeNotAllowed (ironic/common/exception.py:982) | Invalid | 400 | '%(mode)s' boot mode is not allowed for %(op)s operation. | 2 | ironic/api/controllers/v1/utils.py:2283, ironic/conductor/deployments.py:64 |
StepNotAllowed (ironic/common/exception.py:985) | Invalid | 400 | %(step_type)s step '%(step)s' is not allowed. Disallowed by operator configuration [api]disallow_%(step_type)s_steps. | 4 | ironic/api/controllers/v1/node.py:1381, ironic/api/controllers/v1/node.py:1399, ironic/api/controllers/v1/node.py:1416 |
InvalidImage (ironic/common/exception.py:991) | ImageUnacceptable | 500 | The requested image is not valid for use. | 6 | ironic/common/images.py:1016, ironic/common/images.py:1026, ironic/common/images.py:950 |
ImageChecksumError (ironic/common/exception.py:995) | InvalidImage | 500 | The supplied image checksum is invalid or does not match. | 6 | ironic/common/oci_registry.py:878, ironic/common/checksum_utils.py:87, ironic/common/checksum_utils.py:116 |
<!-- /GEN:errors-table -->
3. Situations that matter
| Exception | HTTP | Situation (business terms) | Raised at | Seen by the client as |
|---|---|---|---|---|
NodeLocked | 409 | another operation holds the node's lock (nodes.reservation is set by a conductor) for longer than node_locked_retry_attempts × node_locked_retry_interval (3 × 1 s) | ironic/db/sqlalchemy/api.py:777, ironic/db/sqlalchemy/api.py:785 | 409 faultstring "Node X is locked by host Y, please retry after the current operation is completed."; openstacksdk and ironicclient retry 409 automatically |
NodeLocked (provision API) | 409 | requested transition not possible and the node is reserved: "it is busy" rather than "wrong state" | ironic/api/controllers/v1/node.py:1282 | 409 |
InvalidStateRequested | 400 | requested verb not allowed from the current provision state (e.g. provide on an active node) | ironic/api/controllers/v1/node.py:1282, ironic/conductor/manager.py:1458 | 400 "The requested action "provide" can not be performed on node "X" while it is in state "active"." |
NotAcceptable | 406 | verb, field or parameter newer than the requested microversion (check_allow_management_verbs, allow_*) | ironic/api/controllers/v1/utils.py:935 | 406 "Request not acceptable." — python-ironicclient negotiates a new version on 406 |
NodeInMaintenance | 400 | deploy/rebuild/provide/clean on a node in maintenance (maintenance blocks provisioning unless [conductor]/allow_provisioning_in_maintenance) | ironic/api/controllers/v1/node.py:1274, ironic/conductor/manager.py:1458 | 400 |
NodeAssociated | 409 | deleting or re-associating a node that has an instance_uuid | ironic/conductor/manager.py:2348 | 409 |
InstanceAssociated | 409 | setting instance_uuid on a node while another node has it (Nova's reservation race) | ironic/db/sqlalchemy/api.py:1015 | 409; Nova's update_node(..., retry_on_conflict=False) turns it into a failed build |
NodeProtected | 403 | undeploy, rebuild or delete of a protected node (1.48+) | ironic/conductor/manager.py:1089, ironic/conductor/manager.py:2352 | 403 |
NoFreeConductorWorker | 503 | the conductor's worker pool ([conductor]/workers_pool_size, 300, plus a reserved 5 %) is full | ironic/conductor/base_manager.py:555 | 503 "Requested action cannot be performed due to lack of free conductor workers."; retried by SDK/ironicclient |
TemporaryFailure | 503 | no live conductor (the hash ring is empty) | ironic/common/hash_ring.py:108, ironic/conductor/rpcapi.py:278 | 503 |
NoValidHost | 404/400 | no live conductor supports the node's hardware type in its conductor group | ironic/conductor/rpcapi.py:247 | 400 on writes/ramdisk endpoints |
InvalidParameterValue | 400 | the generic validation error (217 raise sites): bad driver_info, bad steps, invalid agent token (ironic/conductor/manager.py:3554), interface not enabled… | many | 400 with the specific text |
MissingParameterValue | 400 | required driver_info field missing (e.g. redfish_address, ipmi_address) when validating an interface | ironic/drivers/modules/redfish/utils.py:168, ironic/drivers/modules/ipmitool.py:350 | 400 on GET …/validate, deploy refused |
IncompleteLookup | 400 | lookup without MAC nor UUID | ironic/api/controllers/v1/ramdisk.py:171 | 400 |
HTTPForbidden | 403 | ramdisk endpoints disabled ([api]/enable_ramdisk_endpoints = false) | ironic/api/controllers/v1/ramdisk.py:160 | 403 |
AgentConnectionFailed | 500 | the conductor cannot reach the agent's callback_url (port 9999) | ironic/drivers/modules/agent_client.py:116 | not seen by API clients: during cleaning it moves the node to clean wait to retry on the next heartbeat (ironic/conductor/cleaning.py:301); during deploy the node fails |
AgentInProgress | 409 | the agent answered 409 / "agent is busy" to a new command | ironic/drivers/modules/agent_client.py:300 | not seen by API clients: the step is retried at the next heartbeat |
AgentAPIError | 500 | the agent answered ≥ 400 to a command | ironic/drivers/modules/agent_client.py:303 | step failure → *failed state with last_error |
AgentCommandTimeout | 500 | a polled command did not finish within command_wait_attempts × command_wait_interval (100 × 6 s) | ironic/drivers/modules/agent_client.py:181 | step failure |
PowerStateFailure | 409 | the BMC did not reach the requested power state within the timeout | ironic/conductor/utils.py:286 | async: last_error, target_power_state cleared |
RedfishConnectionError, RedfishError | 500 | BMC unreachable, authentication failure, Redfish error payload | ironic/drivers/modules/redfish/utils.py:285 | validation 400 at GET …/validate; async errors in last_error; power sync puts the node in maintenance after 3 failures |
IPMIFailure | 500 | ipmitool exited non-zero after the retries | ironic/drivers/modules/ipmitool.py:645 | as above |
ImageRefValidationFailed, ImageNotFound, ImageDownloadFailed | 500/404 | the image href (Glance id, HTTP URL, OCI) cannot be resolved or downloaded by the conductor | ironic/common/glance_service/image_service.py:58 | deploy fails; last_error |
StepNotAllowed | 400 | a user step is in [api]/disallow_{clean,deploy,service}_steps | ironic/conductor/steps.py:582 | 400 |
NotAuthorized | 403 | a step-level policy baremetal:step:execute:<iface>.<step> refuses the caller | ironic/conductor/steps.py:791 | 403 "insufficient privileges to execute step …" |
4. Asynchronous errors
Most provisioning failures never reach the API caller: the RPC call returned 202 long before. They are visible as:
| Where | What | Set by |
|---|---|---|
node.provision_state | deploy failed, clean failed, inspect failed, rescue failed, unrescue failed, adopt failed, service failed, or error (failed tear-down) | fail events from the error handlers: ironic/conductor/utils.py:488 (provisioning_error_handler), ironic/conductor/utils.py:544 (cleaning), ironic/conductor/utils.py:715 (deploying), ironic/conductor/utils.py:2079 (servicing), ironic/drivers/modules/deploy_utils.py:255 (set_failed_state) |
node.last_error | human-readable cause, e.g. "Timeout reached while waiting for callback for node X" (deploy wait), "Node X failed step {...}: <error>", "By request, the clean operation was aborted…" | same handlers; TaskManager._write_exception records "Async execution of <method> failed with error: …" when a spawned worker raises (ironic/conductor/task_manager.py:485) |
node.maintenance + maintenance_reason + fault | power failure (power sync failed power_state_sync_max_retries times), clean failure (orphaned cleaning), rescue abort failure, service failure | ironic/conductor/manager.py:4524, ironic/conductor/manager.py:1950 |
node history (GET …/history) | every error event with its type (provisioning, takeover, conductor, console…) | ironic/conductor/utils.py:1914 |
allocation state: error, last_error | "no available nodes match the resource class X", "could not reserve any of N suitable nodes" | ironic/conductor/allocations.py:85 |
| notifications | baremetal.node.provision_set.error, baremetal.node.power_set.error… (priority ERROR) | ironic/conductor/task_manager.py:508 |
Timeouts that produce these failures (all in 05): [conductor]/deploy_callback_timeout, clean_callback_timeout, inspect_wait_timeout, rescue_callback_timeout, service_callback_timeout (1800 s each).
5. Key log messages
| Level | Message | Situation | Source |
|---|---|---|---|
| ERROR | Node %(node)s moved to provision state "%(state)s" from state "%(previous)s"; target provision state is "%(target)s" | every transition into a *failed or error state (INFO otherwise) | ironic/conductor/task_manager.py:615 |
| WARNING | We have exceeded the normal maximum time window to complete a node lock attempting to reserve node %(node)s for purpose %(purpose)s. | lock contention | ironic/conductor/task_manager.py:368 |
| ERROR | Invalid or missing agent_token received for node %(node)s | heartbeat with a wrong token: a stale ramdisk, or an attacker on the provisioning network | ironic/conductor/manager.py:3599 |
| ERROR | Received heartbeat for node %(node)s with callback URL %(url)s. This is not expected, and the heartbeat will not be processed. | callback URL changed: two ramdisks claiming the same node | ironic/api/controllers/v1/ramdisk.py:289 |
| ERROR | Lookup is not allowed for node %(node)s in the provision state %(state)s | ramdisk booted while the node is not waiting for it | ironic/api/controllers/v1/ramdisk.py:188 |
| WARNING | During sync_power_state, could not get power state for node %(node)s, attempt %(attempt)s of %(retries)s. Error: %(err)s. | BMC unreachable | ironic/conductor/manager.py:4624 |
| ERROR | Server-side error: "%s". Detail: … | any 5xx produced by the API | ironic/api/method.py:114 |
| CRITICAL | Failed to start keepalive | conductor cannot run its DB heartbeat; it exits | ironic/conductor/base_manager.py:308 |
Source: reverse-spec-ironic/02-errors_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.