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

Reverse-spec · Services

glance — Errors

Errors — glance — branch stable/2026.2

Branch stable/2026.2 @ a3e5f490b7a2 — repository https://opendev.org/openstack/glance — analysed on 2026-10-28

Glance's exceptions (glance/common/exception.py, 86 classes) carry no HTTP status: GlanceException only formats message with its keyword arguments (glance/common/exception.py:31). Each handler converts the exceptions it expects into webob.exc.HTTP* (287 conversions found in the code), and anything left unconverted becomes a 500 in wsgi.Resource (glance/common/wsgi.py:516-522). There is no business error code: the client only gets the status and an explanation text (see Error body).

Error body

Glance returns webob's default error page, negotiated on the Accept header of the request (checked with the webob of the analysis venv and in the recorded exchanges, _rewrite/exchanges_stable-2026.2.json):

AcceptContent-TypeBody
absenttext/plain; charset=UTF-8404 Not Found\n\nImage x not found.\n\n
application/jsonapplication/json{"message": "Image x not found.<br /><br />\n\n\n", "code": "404 Not Found", "title": "Not Found"}
text/html, */*text/html<html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1>Image x not found.<br /><br />…</body></html>
  • The explanation is translated to the request's Accept-Language when a catalog exists (glance/common/wsgi.py:442-459).
  • There is no error code and no structured field: clients that need the reason parse the text (see 07 § 4).
  • In the JSON form, message keeps webob's HTML line breaks (<br /><br />) and trailing newlines.
  • Every error response also carries x-openstack-request-id (glance/api/middleware/context.py:72-85).
  • A few handlers return 204 with an empty body where an error could be expected (download of an image whose data disappeared, glance/api/v2/image_data.py:678-679) or a 405 with a custom body template (DELETE /v2/tasks/{id}, glance/api/v2/tasks.py:158-165).

Exception → HTTP translation

  • Where: in each controller (glance/api/v2/*.py) and in two cross-cutting layers:
    • the v2 policy layer (glance/api/v2/policy.py) raises HTTPForbidden directly, and turns it into 404 when the caller cannot see the image or metadef namespace (glance/api/v2/policy.py:173-193, glance/api/v2/policy.py:335-347): a refused action on an invisible image looks exactly like a missing image;
    • the notifier layer (glance/notifier.py:436-503) catches store errors raised during set_data, emits an image.upload ERROR notification and re-raises them as webob.exc.HTTP*, so that upload errors keep a defined status whatever the caller.
  • What falls through to 500: any exception not listed by the handler. wsgi.Resource logs Caught error: … with the traceback and returns a bare HTTPInternalServerError (glance/common/wsgi.py:516-522). Known cases: an unexpected store exception on delete_from_store and on location removal is turned into 500 on purpose, with the store message as explanation (glance/api/v2/images.py:820-822, glance/api/v2/images.py:1156-1159); SessionInitError of oslo.limit (misconfigured unified limits) is re-raised and becomes 500 (glance/quota/keystone.py:65-73).
  • Same exception, different statuses (traps for clients):
ExceptionStatusWhere
InvalidImageStatusTransition400DELETE /v2/images/{id} (glance/api/v2/images.py:958-959), deactivate/reactivate (glance/api/v2/image_actions.py:72-73)
InvalidImageStatusTransition409upload, stage, import (glance/api/v2/image_data.py:238-240, glance/api/v2/images.py:503-504)
exception.Invalid404DELETE /v2/stores/{store}/{image} when the image has no location in that store (glance/api/v2/images.py:799-805)
exception.Invalid400everywhere else
exception.Forbidden404image members show (glance/api/v2/image_members.py:305-312), metadef reads, image actions on invisible images (policy layer)
exception.NotFound / Forbidden404 without explanationGET /v2/images/{id}/tasks (glance/api/v2/images.py:608-609)
glance_store.NotFound204 (empty body)GET /v2/images/{id}/file when the data is gone from the store (glance/api/v2/image_data.py:678-679)
glance_store.NotFound, ImageNotFound, Conflict410upload when the image was deleted during the upload (glance/api/v2/image_data.py:185-201)

Catalogue

One row per situation. "Client sees" is the status after translation; 500 means not translated.

Images and image data

ExceptionMessage (template)SituationRaised atClient sees
ImageNotFound (NotFound)"Image with the given id %(image_id)s was not found"the image does not exist, is deleted, or is not visible to the callerglance/db/__init__.py:73-76404
Forbidden"You are not authorized to complete %(action)s action."the image is not mutable by the caller (owner check in the DB layer)glance/db/sqlalchemy/api.py:135-146403, or 404 if the image is invisible
ProtectedImageDelete (Forbidden)"Image %(image_id)s is protected and cannot be deleted."DELETE of an image with protected = trueglance/domain/__init__.py:251403
InvalidImageStatusTransition (Invalid)"Image status transition from %(cur_status)s to %(new_status)s is not allowed"the image state machine refuses the change, e.g. upload to an active image, delete of a deleted imageglance/domain/__init__.py:155409 (data, import) or 400 (delete, actions)
ValueError "Properties %s must be set prior to saving data."—upload, stage or import without disk_format and/or container_formatglance/domain/__init__.py:159-170400 (upload: "…"; import checks it first with 409 "'container_format' needs to be set before import")
Forbidden "Not allowed to deactivate image in status '%s'"—deactivate an image that is not active/deactivatedglance/domain/__init__.py:257-268403
Forbidden "Not allowed to reactivate image in status '%s'"—reactivate an image that is not deactivated/activeglance/domain/__init__.py:270-281403
Forbidden "The requested image has been deactivated. Image data download is forbidden."—download of a deactivated image by a non-adminglance/api/v2/image_data.py:483-487403
ReadonlyProperty (Forbidden)"Attribute '%(property)s' is read-only."create with a read-only attribute (status, size, checksum…)glance/domain/__init__.py:58403
ReservedProperty (Forbidden)"Attribute '%(property)s' is reserved."create or PATCH with location, deleted, deleted_at or an os_glance_* property; property protectionsglance/domain/__init__.py:65-69, glance/api/property_protections.py:41403
DuplicateLocation (Duplicate)"The location %(location)s already exists"the same URL twice in locationsglance/location.py:230, glance/location.py:273400
BadStoreUri"The Store URI was malformed."a location URL that no configured store accepts, or that the store cannot reachglance/location.py:148, glance/location.py:164400
InvalidImageData (Invalid)"Image data is not acceptable or does not match parameters"the uploaded bytes do not match disk_format, or fail the GPT/MBR safety checks, or format inspection failed with require_image_format_matchglance/location.py:612, glance/location.py:665, glance/location.py:688, glance/location.py:693415
cursive SignatureVerificationError"Signature verification failed"img_signature* properties present and the data does not match the signatureglance/location.py:556400
UploadException"Image upload problem: %s"the store returned a size or hash different from the value already recorded on the imageglance/location.py:572500 [inferred: not caught by the upload handler]
StorageQuotaFull"The size of the data %(image_size)s will exceed the limit. %(remaining)s bytes remaining."legacy user_storage_quota exceeded, before or after the writeglance/api/common.py:187, glance/api/common.py:196413
ImageSizeLimitExceeded"The provided image is too large."more than image_size_cap bytes (default 1 TiB)glance/db/__init__.py:183, glance/db/__init__.py:197, glance/common/utils.py:467413
LimitExceeded(oslo.limit message)unified limits: image_size_total, image_stage_total, image_count_total or image_count_uploading exceededglance/quota/keystone.py:64413
ImagePropertyLimitExceeded (LimitExceeded)"The limit has been exceeded on the number of allowed image properties. Attempted: %(attempted)s, Maximum: %(maximum)s"more than image_property_quota (128) propertiesglance/quota/__init__.py:113413
ImageTagLimitExceeded"…number of allowed image tags…"more than image_tag_quota (128) tagsglance/quota/__init__.py:46413
ImageLocationLimitExceeded (LimitExceeded)"…number of allowed image locations…"more than image_location_quota (10) locationsglance/quota/__init__.py:86413
ImageMemberLimitExceeded"…number of allowed image members for this image…"more than image_member_quota (128) membersglance/quota/__init__.py:204413
Conflict "Image has active task"—another import or add-location holds the image lock and it has not expiredglance/api/v2/images.py:220409
Conflict "New operation on image '%s' is not permitted as prior operation is still in progress"—lost the race to take the import lockglance/api/v2/images.py:481-484, glance/api/v2/images.py:1226-1230409
Conflict (import preconditions)"Image with status active cannot be target for import", "Only images with status active can be targeted for copying", "Image needs to be in 'queued' state to use '%s' method", "Image needs to be staged before 'glance-direct' method can be used", "'container_format' needs to be set before import", "'disk_format' needs to be set before import"POST /v2/images/{id}/import on an image in the wrong stateglance/api/v2/images.py:335-357409

Store errors (glance_store)

Store exceptionSituationClient seesTranslated at
StorageFullthe backend has no space left413glance/api/v2/image_data.py:251-257
StorageWriteDeniedthe backend refused the write503glance/api/v2/image_data.py:287-293
StoreAddDisabledthe store is read-only (http)410glance/api/v2/image_data.py:230-236
Duplicatedata already present for this image id (staging)409 "The image %s has data on staging"glance/api/v2/image_data.py:406-408
TimeoutErrorfilesystem store operation timed out503glance/api/v2/images.py:125-128, glance/api/v2/image_data.py:294-299
NotFounddownload: no data at the location204 empty bodyglance/api/v2/image_data.py:678-679
RemoteServiceUnavailabledownload: the remote store (HTTP location, Swift…) is unreachable503glance/api/v2/image_data.py:680-681
StoreGetNotSupported, StoreRandomGetNotSupporteddownload or Range request not supported by the store400glance/api/v2/image_data.py:682-684
InUseByStore, HasSnapshotdelete: the data is in use (e.g. RBD clones)409glance/api/v2/images.py:943-951
UnknownSchemeupload or import names a store that does not exist400 (upload), 409 (import)glance/api/v2/image_data.py:124-127, glance/api/v2/images.py:398-400

Request validation (deserializers)

MessageSituationClient seesRaised at
"Malformed JSON in request body." / "Unexpected body type. Expected list/dict."body is not JSON, or not an object/array400glance/common/wsgi.py:404-413
"Body expected in request."POST/PATCH without body400glance/api/v2/images.py:1313-1318
"A body is not expected with this request."body sent to a route marked body_reject (GET, DELETE…)400glance/common/wsgi.py:500-502
"Attribute '%s' is read-only."create with direct_url, self, file, schema, stores403glance/api/v2/images.py:1321-1325
"Custom property should not be greater than 255 characters."property name longer than 255400glance/api/v2/images.py:1351-1355
JSON schema error text (InvalidObject)the body does not match /v2/schemas/image, member, task, metadef schemas400glance/schema.py:38
(Accept-Patch header)PATCH with a content type other than application/openstack-images-v2.0-json-patch or …-v2.1-json-patch415 with Accept-Patchglance/api/v2/images.py:1509-1521
"Invalid sort key: …", "Invalid sort direction: …", "limit param must be an integer", "limit param must be positive", "Invalid status: …", "Invalid visibility value: …", "The \"changes-since\" filter is no longer available on v2."bad list parameters400glance/api/v2/images.py:1552-1599
"Invalid value '%s' for 'os_hidden' filter." / "'protected' filter"filter values other than true/false400glance/api/v2/images.py:529-541
(unsupported media type)upload or stage with a content type other than application/octet-stream415glance/api/v2/image_data.py:572-575, glance/api/v2/image_data.py:587-590
"Invalid or missing image size in request headers."non-integer x-openstack-image-size400glance/api/v2/image_data.py:557-569
"'glance-direct' method is not available at this site."stage while glance-direct is not in enabled_import_methods404glance/api/v2/image_data.py:584-586
"Unknown import method name '%s'."import method not in enabled_import_methods400glance/api/v2/images.py:1709-1711
"URI for web-download does not pass filtering: %s" / "URI for add location does not pass filtering: %s"URL refused by [import_filtering_opts]400glance/api/v2/images.py:462-466, glance/api/v2/images.py:1195-1201
"Error decoding your request. Either the URL or the request body contained characters that could not be decoded by Glance"non-UTF-8 URL or body400glance/common/wsgi.py:511-515

Members, tags, tasks

Exception / messageSituationClient seesRaised at
"Only shared images have members."member operation on an image whose visibility is not shared403glance/api/v2/image_members.py:77-80
Duplicate "Member %(member_id)s is duplicated for image %(image_id)s"the project is already a member409glance/api/v2/image_members.py:172-177
"%(m_id)s not found in the member list of the image %(i_id)s."unknown member404glance/api/v2/image_members.py:113-118
ValueError "Incorrect request: …"member status other than pending, accepted, rejected400glance/api/v2/image_members.py:229-232, glance/domain/__init__.py:335-338
TaskNotFoundunknown or expired task404glance/db/sqlalchemy/api.py:1998
InvalidTaskType / InvalidTaskStatustask type other than import, api_image_import, location_import400 [inferred: via Invalid]glance/domain/__init__.py:364, glance/domain/__init__.py:367
"This operation is currently not permitted on Glance Tasks. They are auto deleted after reaching the time based on their expires_at property."DELETE /v2/tasks/{id}405 with Allow: GETglance/api/v2/tasks.py:158-165

Metadata definitions

ExceptionMessage (template)SituationClient seesRaised at
MetadefDuplicateNamespace (Duplicate)"The metadata definition namespace=%(namespace_name)s already exists."create or rename to an existing namespace409glance/db/sqlalchemy/metadef_api/namespace.py
MetadefDuplicateObject, …Property, …Tag, …ResourceType, …ResourceTypeAssociation (Duplicate)"… already exists in namespace=%(namespace_name)s."name already used in the namespace409glance/db/sqlalchemy/metadef_api/
MetadefNamespaceNotFound, MetadefObjectNotFound, MetadefPropertyNotFound, MetadefTagNotFound, MetadefResourceTypeNotFound, MetadefResourceTypeAssociationNotFound (NotFound)"… was not found …"unknown name404glance/db/sqlalchemy/metadef_api/
MetadefForbidden (Forbidden)"You are not authorized to complete this action."private namespace of another project404 (hidden by the policy layer) or 403glance/db/sqlalchemy/metadef_api/namespace.py:99, glance/db/sqlalchemy/metadef_api/namespace.py:121
MetadefIntegrityError (Forbidden)"The metadata definition %(record_type)s with name=%(record_name)s not deleted. Other records still refer to it."delete of a namespace or resource type still referenced403glance/db/sqlalchemy/metadef_api/namespace.py:270, glance/db/sqlalchemy/metadef_api/resource_type.py:102
ProtectedMetadefResourceTypeSystemDelete (Forbidden)"Metadata definition resource-type %(resource_type_name)s is a seeded-system type and cannot be deleted."delete of a seeded resource type403glance/db/sqlalchemy/metadef_api/resource_type.py:92
ProtectedMetadefNamespaceDelete, …NamespacePropDelete, …ObjectDelete, …ResourceTypeAssociationDelete, …TagDelete (Forbidden)"… is protected and cannot be deleted."delete inside a protected namespace403glance/domain/__init__.py:544, glance/domain/__init__.py:582, glance/domain/__init__.py:616, glance/domain/__init__.py:645, glance/domain/__init__.py:672

Asynchronous errors

These never reach the client as an HTTP status. The client sees them through the image (status, os_glance_failed_import, os_glance_importing_to_stores) and the task (status = failure, message) returned by GET /v2/images/{id} and GET /v2/images/{id}/tasks.

SituationVisible effectLogDefined at
quota exceeded when the import startstask failure, image back to queuedFailed to execute task [inferred]glance/async_/flows/api_image_import.py:891
web-download URL unreachable or refused at fetch timetask failure, image queued"Task %(task_id)s failed with exception %(error)s"glance/async_/flows/_internal_plugins/web_download.py:51-67
glance-download: remote image not active_InvalidGlanceDownloadImageStatus "Source image status should be active instead of %s"sameglance/async_/flows/api_image_import.py:840-843
glance-download: size mismatchImportTaskError "Task %(task_id)s failed because downloaded data size %(data_size)i is different from expected %(expected)i"—glance/async_/flows/_internal_plugins/glance_download.py:72-78
glance-download: no endpoint for the regionGlanceEndpointNotFound "%(interface)s glance endpoint not found for region %(region)s"—glance/async_/utils.py:94
copy-image: no readable locationNotFound "Image not found in any configured store""Image: %(img_id)s is not present in store …"glance/async_/flows/_internal_plugins/copy_image.py:108-114
conversion refused (format mismatch, VMDK type, qemu-img error)RuntimeError with the reason; task failure"Image claimed to be %s format but format inspection …"glance/async_/flows/plugins/image_conversion.py:114-241
all stores failed_NoStoresSucceeded "None of the uploads finished!"—glance/async_/flows/api_image_import.py:735-739
one store failed with all_stores_must_succeed = falsestore listed in os_glance_failed_import, image active"%(task_id)s of %(task_type)s failed but since all_stores_must_succeed is set to false, continue."glance/async_/flows/api_image_import.py:673-682
task no longer processing during a writeTaskAbortedError, write stopped"Task %(task)s expected \"processing\" status, but found \"%(status)s\"; aborting."glance/async_/flows/api_image_import.py:687-705
location hash failed http_retries times_HashCalculationFailed; image back to queued if not active—glance/async_/flows/location_import.py:85-103
hash calculation canceled by an image delete_HashCalculationCanceled—glance/async_/flows/location_import.py:71-72
validation data does not match the computed hashInvalidParameterValue, image back to queued—glance/async_/flows/location_import.py:164-177
import lock stolen (stale task)old task failure "Expired lock preempted""Image %(image)s has stale import task %(task)s in status %(status)s from %(owner)s; removed lock because it had expired."glance/api/v2/images.py:135-169
scrubber cannot delete a locationlocation stays pending_delete, retried next run"Failed to delete image %(image_id)s location …" [inferred: wording]glance/scrubber.py:390-414

Key log messages

LevelMessageSituationDefined at
ERROR"Caught error: %s" (with traceback)any unexpected exception in a handler → 500glance/common/wsgi.py:520
ERROR"Failed to initialize oslo_limit, likely due to incorrect or insufficient configuration: %(err)s"unified limits misconfiguredglance/quota/keystone.py:66
WARNING"Import methods are enabled but staging directory %(path)s does not exist; Imports will fail!"startup without staging directoryglance/common/wsgi_app.py:159-162
WARNING"Image %(image)s has active import task %(task)s in status %(status)s; lock remains valid for %(expire)i more seconds"import refused with 409 because of a valid lockglance/api/v2/images.py:207-213
WARNING"Image claims %r disk_format but is actually %r"raw upload whose content is a known formatglance/location.py:647
ERROR"Glance tried all active locations to get data for image %s but all have failed."download or copy failed on every locationglance/location.py:733
ERROR"Failed to proxy to %r: %s"the worker holding staged data cannot be reachedglance/api/v2/images.py:279, glance/api/v2/images.py:282
INFO"Unable to create trust: %s Use the existing user token."upload without a trust (e.g. no Keystone token info)glance/api/v2/image_data.py:156-158
ERROR"Checksum header is missing."cache middleware cannot verify a response it would cacheglance/api/middleware/cache.py:275

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