Skip to content

Unmeterable Usage Event

URI: https://docs.ankatech.co/errors/unmeterable-usage-event
HTTP Status: 400 Bad Request

When you see this

A usage event could not be attributed or named, so the License Server refused it rather than recording it with the offending field erased or substituted: a usage row whose subject or algorithm cannot be resolved cannot be reconciled, and a fabricated value is indistinguishable at rest from an operation the platform actually performed. The error direction is deliberately safe — a refused record can only ever under-bill, never over-bill.

This problem type has exactly ONE HTTP disposition

There is no usage-report endpoint and no license.report scope: usage reaches the service only over the platform's internal event stream. So the two ways this condition surfaces are:

  • HTTP 400, on GET /api/licenses/{tenantId}/clients/{clientId}/status only, and only for the cross-tenant case below.
  • No HTTP response at all, on the Kafka path. An unmeterable event is classified not-retryable and quarantined to a dead-letter topic. There is no caller to answer, so there is no status code to look for.

Common Causes

  • (HTTP 400 and Kafka) The named client belongs to a different tenant than the one the request or event claims — metering it would attribute one tenant's operation to another. On /status this is refused rather than answered: replying would confirm that another tenant holds that client id.
  • (HTTP 400 and Kafka) tenantId or clientId is absent or is not a valid UUID, so the subject cannot be identified. On /status a malformed path variable answers type: .../invalid-input instead; this problem type covers the cross-tenant case.
  • (Kafka only) The algorithm, sourceAlgorithm or targetAlgorithm field named a value the platform's algorithm catalogue does not declare. Absence is legal — some metered operations genuinely have no algorithm — and only an unrecognised value is refused.
  • (Kafka only) The processingMode component is absent (mode_absent) or is not one of STREAMING / NON_STREAMING (mode_unknown). Unlike the algorithm, absence here is not legal: the two streaming counters partition every billable event, so a defaulted mode would record a different operation, not less of one. mode_absent on a freshly deployed meter is the signature of a producer that still omits the tenth component — see the streaming metering cutover runbook*.

The detail names the field and never echoes the submitted value; on /status it names neither the tenant nor the client.

Response Example

{
  "type": "https://docs.ankatech.co/errors/unmeterable-usage-event",
  "title": "Unmeterable Usage Event",
  "status": 400,
  "detail": "the named client belongs to a different tenant; metering it would attribute one tenant operation to another",
  "instance": "/api/licenses/f47ac10b-58cc-4372-a567-0e02b2c3d479/clients/a1b2c3d4-e5f6-4a5b-8c7d-9e8f7a6b5c4d/status"
}

Content-Type: application/problem+json — the response follows RFC 9457 Problem Details.

How to Resolve

  1. Read the detail: it names the field that could not be resolved. The submitted value is not echoed, but the caller already has it.
  2. On /status (HTTP 400), send a clientId that belongs to the tenantId in the same path. Nothing was recorded, so there is no partial row to clean up.
  3. On the Kafka path (no HTTP response), the event is held in a dead-letter topic for inspection by the deployment's operator. For a subject failure, the producer emitted an event whose tenantId/clientId pair is not coherent; for an algorithm failure, it named a value the catalogue does not declare. Any accepted spelling resolves to the canonical name, so two spellings of one algorithm aggregate onto one billing line. The fix belongs at the producer — a replay of an uncorrected event is refused identically.
  4. There is no endpoint to resubmit a usage report to. POST /api/licenses/report does not exist: it answers 404 authenticated, 401 anonymous.

For full schema definitions, examples, and interactive testing, see the Developer Hub Reference.

* restricted content — see higher-tier documentation