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

Reverse-spec · Services

cloudkitty — Errors

Error codes and messages — CloudKitty — branch stable/2026.2

Branch stable/2026.2 @ 0685cc330e83 — repository https://opendev.org/openstack/cloudkitty — analysed on 2026-11-09

CloudKitty has no structured error code: errors are an HTTP status plus a free-text message, and the body format depends on the API version. Processor errors never reach a client: they appear in logs and, at most, as a scope that stops advancing.

1. Exception → HTTP translation

1.1 v1 (Pecan + WSME)

MechanismBehaviourWhere
pecan.abort(code, msg) in handlersthe explicit way v1 returns 4xxe.g. cloudkitty/rating/hash/controllers/mapping.py:182-185
PolicyNotAuthorized (has code = 403)raised by policy.authorize; under module_config it is caught and turned into pecan.abort(403, msg)cloudkitty/common/policy.py:41-50, cloudkitty/rating/__init__.py:139-143
other v1 controllersPolicyNotAuthorized propagates to WSME, which uses the exception's code → 403**[inferred: wsmeext.pecan / wsme.api.format_exception]**
WSME type validationwrong type, bad UUID (UuidType.validate), bad enum, missing mandatory attribute → 400cloudkitty/api/v1/types.py:27-36, cloudkitty/rating/hash/datamodels/mapping.py:23-44 **[inferred: WSME InvalidInput]**
any other exception500[inferred]

Body [inferred: WSME JSON error format]:

{"faultcode": "Client", "faultstring": "No such mapping: 6b1b…", "debuginfo": null}

faultcode is Server for 5xx.

1.2 v2 (Flask + flask-restful)

MechanismBehaviourWhere
werkzeug.exceptions.BadRequest/NotFound/Forbidden raised in handlersstatus of the exceptione.g. cloudkitty/api/v2/dataframes/dataframes.py:106-108
PolicyNotAuthorizedcaught by BaseResource.dispatch_request → 403 You are not authorized to perform this actioncloudkitty/api/v2/base.py:29-34
schema validation (voluptuous.Invalid)400 Invalid data '<args>' : <msg> (path: '<path>')cloudkitty/api/v2/utils.py:189-195
voluptuous.Invalid raised inside a handlernot caught → 500cloudkitty/api/v2/summary/summary.py:54-57 [inferred]
any other exception (storage, DB, RPC)500**[inferred: flask-restful handle_error]**

Body [inferred: flask-restful]: {"message": "<description>"}.

1.3 Authentication

keystonemiddleware answers 401 before the application for every path except /, /v1, /v2 (cloudkitty/api/middleware.py:29-36, etc/cloudkitty/api_paste.ini:20-22).

2. Catalogue of exceptions

2.1 HashMap (cloudkitty/rating/hash/db/api.py)

All derive from ClientHashMapError (cloudkitty/rating/hash/db/api.py:38), so a handler's except ClientHashMapError → 400 also catches the "not found" ones when no more specific branch precedes it.

ExceptionMessage templateSituationRaised atClient sees
ClientHashMapErrorfree textYou must specify either name or uuid. (service lookup/delete without key)cloudkitty/rating/hash/db/sqlalchemy/api.py:50-51, cloudkitty/rating/hash/db/sqlalchemy/api.py:596-597400 / 500 depending on handler
You can only specify one parent. — mapping/threshold with both service_id and field_idcloudkitty/rating/hash/db/sqlalchemy/api.py:311-312, cloudkitty/rating/hash/db/sqlalchemy/api.py:455-456400
You must specify one parent.cloudkitty/rating/hash/db/sqlalchemy/api.py:313-314, cloudkitty/rating/hash/db/sqlalchemy/api.py:457-458400
You can't specify a value and a service_id.cloudkitty/rating/hash/db/sqlalchemy/api.py:315-318400
You must specify a value for a field mapping. (create, or update setting value to empty)cloudkitty/rating/hash/db/sqlalchemy/api.py:319-322, cloudkitty/rating/hash/db/sqlalchemy/api.py:510-513400
You must specify either service_uuid, field_uuid or group_uuid. — threshold list without parentcloudkitty/rating/hash/db/sqlalchemy/api.py:235-238500 (not caught by get_all) [inferred]
No such attribute: <name> / No attribute to update.cloudkitty/rating/hash/db/sqlalchemy/api.py:525-533, cloudkitty/rating/hash/db/sqlalchemy/api.py:565-573400
NoSuchServiceNo such service: %(name)s (UUID: %(uuid)s)unknown service id/namecloudkitty/rating/hash/db/sqlalchemy/api.py:54-55, cloudkitty/rating/hash/db/sqlalchemy/api.py:599-600404 on GET/DELETE service; 400 when it is the parent of a new field/mapping/threshold
NoSuchFieldNo such field: %sunknown field idcloudkitty/rating/hash/db/sqlalchemy/api.py:76-77, cloudkitty/rating/hash/db/sqlalchemy/api.py:609-610404 on GET/DELETE field; 400 as a parent
NoSuchGroupNo such group: %(name)s (UUID: %(uuid)s)unknown group idcloudkitty/rating/hash/db/sqlalchemy/api.py:91-92, cloudkitty/rating/hash/db/sqlalchemy/api.py:620-621404 on GET/DELETE group; 400 when referenced by a mapping/threshold
NoSuchMappingNo such mapping: %sunknown or already soft-deleted mapping (update/delete filter deleted IS NULL)cloudkitty/rating/hash/db/sqlalchemy/api.py:102-103, cloudkitty/rating/hash/db/sqlalchemy/api.py:543-544, cloudkitty/rating/hash/db/sqlalchemy/api.py:639-640404
NoSuchThresholdNo such threshold: %sunknown thresholdcloudkitty/rating/hash/db/sqlalchemy/api.py:125-126, cloudkitty/rating/hash/db/sqlalchemy/api.py:583-584, cloudkitty/rating/hash/db/sqlalchemy/api.py:649-650404
NoSuchTypeNo mapping type: %sany other DBError while inserting a mapping/threshold (in practice: invalid enum on a DB that enforces it)cloudkitty/rating/hash/db/sqlalchemy/api.py:440-441, cloudkitty/rating/hash/db/sqlalchemy/api.py:492-493400
ServiceAlreadyExistsService %(name)s already exists (UUID: %(uuid)s)duplicate service namecloudkitty/rating/hash/db/sqlalchemy/api.py:260-264409
FieldAlreadyExistsField %(field)s already exists (UUID: %(uuid)s)duplicate (service, name)cloudkitty/rating/hash/db/sqlalchemy/api.py:278-280409
GroupAlreadyExistsGroup %(name)s already exists (UUID: %(uuid)s)duplicate group namecloudkitty/rating/hash/db/sqlalchemy/api.py:292-294409
MappingAlreadyExistsMapping '%(mapping)s' already exists for %(p_type)s '%(p_id)s', tenant: '%(t_id)s'same name, or same value/tenant/parent/group with an overlapping validity window, or a unique-key violationcloudkitty/rating/hash/db/sqlalchemy/api.py:394-405, cloudkitty/rating/hash/db/sqlalchemy/api.py:428-439, cloudkitty/rating/hash/db/sqlalchemy/api.py:535-542409
ThresholdAlreadyExistsThreshold '%(threshold)s' already exists for %(p_type)s '%(p_id)s', tenant: '%(t_id)s'duplicate (level, parent, tenant)cloudkitty/rating/hash/db/sqlalchemy/api.py:484-491, cloudkitty/rating/hash/db/sqlalchemy/api.py:575-582409
MappingHasNoGroupMapping has no group (UUID: %s)GET …/mappings/group on a mapping without groupcloudkitty/rating/hash/db/sqlalchemy/api.py:138-139404
ThresholdHasNoGroupThreshold has no group (UUID: %s)idem for thresholdscloudkitty/rating/hash/db/sqlalchemy/api.py:151-152404

Defects worth knowing: on a unique-key violation during update, update_mapping/update_threshold build the message with the loop variable value (cloudkitty/rating/hash/db/sqlalchemy/api.py:535-542, cloudkitty/rating/hash/db/sqlalchemy/api.py:575-582); ThresholdAlreadyExists receives four positional arguments where the class takes threshold, parent_id, parent_type, uuid (cloudkitty/rating/hash/db/api.py:159-176) [inferred: misleading message, not a crash].

2.2 Validity-window validation (hashmap mappings, pyscripts)

Raised with pecan.abort(400, …) (cloudkitty/rating/common/validations/fields.py:40-87):

MessageSituation
Cannot create a rule with start in the past. start=[…] current time=[…].start < now and no force=true
Cannot create a rule with start after end. start=[…] end=[…].end < start
You are allowed to update only the attribute [end] as this rule is already running as it started on […]PUT on a running rule changing anything else than end
End date must be in the future. end=[…] current time=[…]PUT setting a past end on a running rule
Cannot update a rule that was already processed and has a defined end date.PUT on a rule that started and has an end

2.3 PyScripts (cloudkitty/rating/pyscripts/db/api.py)

ExceptionMessageSituationRaised atClient sees
NoSuchScriptNo such script: %(name)s (UUID: %(uuid)s)unknown or soft-deleted scriptcloudkitty/rating/pyscripts/db/sqlalchemy/api.py:56, cloudkitty/rating/pyscripts/db/sqlalchemy/api.py:129, cloudkitty/rating/pyscripts/db/sqlalchemy/api.py:149404
ScriptAlreadyExistsScript %(name)s already exists (UUID: %(uuid)s)duplicate namecloudkitty/rating/pyscripts/db/sqlalchemy/api.py:82-84, cloudkitty/rating/pyscripts/db/sqlalchemy/api.py:100-102409
ValueErrorYou must specify either name or uuid. / No such attribute: … / No attribute to update.internal misusecloudkitty/rating/pyscripts/db/sqlalchemy/api.py:49, cloudkitty/rating/pyscripts/db/sqlalchemy/api.py:123-126, cloudkitty/rating/pyscripts/db/sqlalchemy/api.py:140500 [inferred]

A script that raises or is not valid Python is not detected at upload: compile happens in the processor (cloudkitty/rating/pyscripts/__init__.py:62-70), see § 3.

2.4 v1 core

ErrorMessageSituationWhere
404Module not found.unknown rating modulecloudkitty/api/v1/controllers/rating.py:102-103, cloudkitty/api/v1/controllers/rating.py:124-125
409Module is not configurablemodule_config/<module> for a module without controller (noop)cloudkitty/api/v1/controllers/rating.py:136-141
404No mapping for service: <service> (NoSuchMapping)unknown collector mappingcloudkitty/db/api.py:105-111, cloudkitty/api/v1/controllers/collector.py:48-49
405Invalid endpoint: no metrics in current configuration.invalid metric filecloudkitty/api/v1/controllers/info.py:40-42, cloudkitty/api/v1/controllers/info.py:65-67
404<metric_name>unknown metriccloudkitty/api/v1/controllers/info.py:71-72
403Policy doesn't allow %(action)s to be performed.policy refusalcloudkitty/common/policy.py:41-47
500/504—quote: no processor answers within the oslo.messaging timeout (MessagingTimeout)cloudkitty/api/v1/controllers/rating.py:209 [inferred]

InvalidFilter (cloudkitty/api/v1/controllers/report.py:38) is declared but never raised.

2.5 v2

StatusMessageSituationWhere
400Parameter dataframes must not be empty.POST /v2/dataframes with []cloudkitty/api/v2/dataframes/dataframes.py:43-45
400<dict> isn't a valid DataFrame: … / isn't a valid DataPoint (wrapped in Invalid data …)malformed framecloudkitty/dataframe.py:152-153, cloudkitty/dataframe.py:233-234
404No resource found for provided filters.dataframes total 0; no scope matches (GET/PUT/PATCH scope)cloudkitty/api/v2/dataframes/dataframes.py:106-108, cloudkitty/api/v2/scope/state.py:73-75, cloudkitty/api/v2/scope/state.py:134-136, cloudkitty/api/v2/scope/state.py:184-186
404Too many resources found with the same scope_id: %s.PATCH when the id exists for several fetcher/collector/scope_key combinationscloudkitty/api/v2/scope/state.py:188-192
404Cannot create a scope with an already existing scope_id: %s.POST scope for an existing id (a 409 would be expected)cloudkitty/api/v2/scope/state.py:251-256
400Either all_scopes or a scope_id should be specified.PUT scopecloudkitty/api/v2/scope/state.py:119-121
400Variable 'last_processed_timestamp' cannot be empty/None.PUT scopecloudkitty/api/v2/scope/state.py:123-125
400Invalid groupby time option. There is no groupby processing for [%s].groupby=time-x with x ∉ {d,w,m,y}cloudkitty/storage/v2/__init__.py:183-187
400Limit %s exceeds maximum allowed limit of 5000 for Loki storage. …Loki back endcloudkitty/storage/v2/loki/__init__.py:180-183, cloudkitty/storage/v2/loki/__init__.py:218-221
400Empty or blank reason text is not allowed. …reprocesscloudkitty/api/v2/task/reprocess.py:123-127
400End reprocessing timestamp [%s] cannot be less than start reprocessing timestamp [%s]. (arguments swapped in the message)reprocesscloudkitty/api/v2/task/reprocess.py:128-132
400The provided reprocess time window does not comply with the configured collector period. A valid time window near the provided one is %snot aligned on [collect]/periodcloudkitty/api/v2/task/reprocess.py:134-140
400Cannot use 'ALL' with scope ID [%s]. …ALL mixed with idscloudkitty/api/v2/task/reprocess.py:150-155
400Scopes %s scheduled to reprocess [start=%s, end=%s] do not exist.unknown idscloudkitty/api/v2/task/reprocess.py:173-177
400Cannot execute a reprocessing [start|end=%s] for scope [%s] … after the last possible timestamp [%s].window beyond what was processedcloudkitty/api/v2/task/reprocess.py:186-195
400Cannot schedule a reprocessing for scope [%s] for reprocessing time [%s], because it already has a schedule for a similar time range [%s].overlapcloudkitty/api/v2/task/reprocess.py:223-241
400The order [%s] is not valid. Accepted values are %s.GET reprocessescloudkitty/api/v2/task/reprocess.py:289-292
404Module '<id>' not foundv2 rating modulescloudkitty/api/v2/rating/modules.py:72-74, cloudkitty/api/v2/rating/modules.py:92-94
500RuntimeError("Clause [%s] is not allowed …")forbidden word in custom_fields (InfluxDB)cloudkitty/storage/v2/influx.py:260-268 [inferred: not converted to 400]
500InvalidStatusCode, PushError, influxdb client errors, requests errorsstorage back end unreachable or refusingcloudkitty/storage/v2/elasticsearch/client.py:144-148, cloudkitty/storage/v2/loki/client.py:236-241

3. Errors of the processor (never seen by API clients)

ErrorMessage / logSituationEffectWhere
NoDataCollectedCollector '%s' returned no data for resource '%s'; logged at INFO No data collected for metric %s at timestamp %sa metric has no measure for the periodthe metric is skipped; if all metrics are empty the period is still marked processed with a WARNING No usage data for storage scope [%s] … consider de-activating it.cloudkitty/collector/__init__.py:162-172, cloudkitty/orchestrator.py:358-365, cloudkitty/orchestrator.py:433-436
any collection exceptionError while collecting metric %s at timestamp %s: %s. Exiting.back-end error, timeout (collector_request_timeout, 300 s)the whole scope cycle aborts; last_processed_timestamp is not advanced; retried at the next loopcloudkitty/orchestrator.py:366-374, cloudkitty/orchestrator.py:386-389
CollectError<errorType>: <error>Prometheus/Aetos answered status: error or non-JSONas abovecloudkitty/collector/prometheus_base.py:196-207, cloudkitty/collector/exceptions.py:17
PrometheusResponseErrorCould not get a valid json response for {} (response: {})non-JSON bodywrapped in CollectError / PrometheusFetcherErrorcloudkitty/common/prometheus_client.py:36-47
gexceptions.MetricNotFound, BadRequest with Metrics not foundWARNING [%s] Skipping this metric for the current cycle.Gnocchi metric missing for the scopereturns no datacloudkitty/collector/gnocchi.py:335-343
AssociatedResourceNotFoundResource with {}={} could not be found (WARNING)a measure's group has no matching Gnocchi resource for metadatathe point is droppedcloudkitty/collector/gnocchi.py:136-143, cloudkitty/collector/gnocchi.py:482-488
InvalidConfiguration, voluptuous errorsMetric {} already exists…, has duplicates in groupby and metadata, uses MAP mutator but mutate_map is missinginvalid metric fileprocessor/API start fails, or /v1/info answers 405cloudkitty/collector/__init__.py:312-360, cloudkitty/collector/__init__.py:178-188
PrometheusFetcherErrorUnexpected Prometheus server response "{}" for "{}"fetcher response malformedscope list fails → whole loop fails **[inferred: exception propagates out of internal_run]**cloudkitty/fetcher/prometheus.py:123-145
VersionNotAvailableKeystone version you've specified is not supported[fetcher_keystone]/keystone_version not 2 or 3idemcloudkitty/fetcher/keystone.py:73-82
rating module exception (pyscript error, hashmap Decimal conversion of a non-numeric field with a threshold)Error processing scope %s, we will try it again later. + tracebackbad rule or scriptthe scope is stuck on that period until the rule is fixedcloudkitty/orchestrator.py:716-723, cloudkitty/rating/hash/__init__.py:262-265
storage push failureidemback end downstate not advanced; points already committed in earlier chunks stay → possible duplicates on retry [inferred]cloudkitty/orchestrator.py:445-460, cloudkitty/storage/v2/influx.py:194-195
IndexDoesNotExist / InvalidStatusCodeElasticsearch index {} does not existcloudkitty-storage-init on a missing index; _req raises InvalidStatusCode first on a 404init failscloudkitty/storage/v2/elasticsearch/__init__.py:103-112, cloudkitty/storage/v2/elasticsearch/client.py:144-148
UnsupportedContentTypeContent-Type {} is not supported…[storage_loki]/content_type ≠ application/jsondriver load failscloudkitty/storage/v2/loki/client.py:35-36
reprocessing ExceptionScope [%s] scheduled for reprocessing does not seem to exist anymore. / Unexpected number of storage state entries found for scope [%s].the scope state row vanished or is duplicatedthat schedule fails at every loopcloudkitty/orchestrator.py:540-551
update_reprocessing_time missWARNING Trying to update current time to [%s] … could not find a this task in the database. (the format string contains a broken %,)schedule removed while runninglogging error [inferred]cloudkitty/storage_state/__init__.py:419-426
RPC errorsUnsupportedVersion for reload_modules v1.1 [inferred]API casts a version above the endpoint'slogged by oslo.messaging on the processorcloudkitty/api/v1/controllers/rating.py:51-53, cloudkitty/orchestrator.py:122-123

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