Skip to content

Usage Statement Not Finalizable

URI: https://docs.ankatech.co/errors/usage-statement-not-finalizable
HTTP Status: 409 Conflict

When you see this

You asked for a signed usage statement for a month that cannot be stated yet: its figures can still change.

The request is refused and nothing is written. Nothing about the request is wrong — the same request succeeds once the month has become FINAL.

Why a statement waits for a FINAL month

A signed statement is issued only over a month whose state is FINAL, because a statement is a claim that the figures in it are the month's figures. Every month carries one of three states:

State What it means for a statement
OPEN The calendar month has not ended yet (months are delimited in UTC). The figures will still grow
PROVISIONAL The month has ended, but the licence server has not yet established that it ingested all the usage recorded up to the end of it
FINAL Ingestion has been observed complete past the end of the month; the figures will not change, and a statement can be issued

A month becomes FINAL only when all three of these have been observed:

  1. The calendar month has ended.
  2. The licence server's ingestion of usage events has been caught up on every partition past the end of the month, and has stayed caught up for a quiet margin configured by the deployment — one day by default.
  3. At least one usage event timestamped after the end of the month has been ingested.

FINAL is irreversible — a month reported FINAL is never restated — which is why every condition behind it is an observation rather than an elapsed interval. A clock can say the month has ended; it cannot say that everything recorded before the end has arrived.

The detail says which state the month is in

OPEN and PROVISIONAL are different situations, and the detail names the one you are in:

  • OPEN resolves by waiting a known length of time: until the month ends, and then until the quiet margin has elapsed with ingestion caught up.
  • PROVISIONAL usually means only that the quiet margin has not elapsed yet. If it persists, ingestion may be behind, the licence server may not have established its ingestion position (for example after a broker outage or a restart), or the deployment has recorded no usage at all since the month ended. The third condition above is then never met, and the month does not become FINAL until usage is recorded again. This is intended: a month finalized on the strength of silence would be an irreversible claim made from an absence of evidence.

The detail names the month and its state. It carries no figure: a refusal is not a channel for the numbers of a month that is not yet final.

Not the same refusal as its siblings

Four 409 refusals and one 422 can answer POST /api/v3/admin/usage/statements, and each is answered by a different caller action:

Type The condition What you do
usage-statement-not-finalizable The month cannot be stated yet Wait until the month is FINAL
usage-statement-already-issued The month is already stated and this request declares no correction Name what you are correcting
usage-statement-already-superseded The statement you named is no longer the current one Correct the current one instead
usage-statement-coverage-unverifiable (409) The deployment's installation cannot be vouched for Restore the deployment trial sentinel
usage-statement-period-not-covered (422) The month ends before the store's first covered day State a month from that day on; this one never becomes issuable

Unlike its siblings, this refusal says nothing about statements that already exist: it is decided by the month's state alone. A month that is not yet FINAL has no statement, so a correction naming one is refused as not found (404) before its state is considered.

Common Causes

  • A monthly job issues the statement on the first day of the following month, before the quiet margin has elapsed.
  • The request named the current month, or a future one.
  • The deployment recorded no usage after the month ended, so no event past the boundary has been ingested.
  • The licence server's ingestion is behind, or has not re-established its position after a broker or service disruption.

Response Example

{
  "type": "https://docs.ankatech.co/errors/usage-statement-not-finalizable",
  "title": "Usage Statement Not Finalizable",
  "status": 409,
  "detail": "A signed usage statement is issued only over a FINAL month; 2026-09 is PROVISIONAL. A month becomes FINAL when its calendar window has closed AND this service's ingestion of the usage topic has been observed caught up on every partition past the boundary for the declared quiet margin AND an event timestamped after the boundary has been ingested.",
  "instance": "/api/v3/admin/usage/statements",
  "extensions": {
    "requestId": "b51d7c93-0e4a-4f28-9a66-2c8e17f4d0b3"
  }
}

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

The refusal is raised by the licence server and reaches you through the Admin API unchanged: 409 is a member of {400, 402, 404, 409, 422}, the set the relay propagates with its own type, title, detail and status. You therefore read "not yet", not a 502 reporting an outage. instance and the correlation identifier are always the Admin API's own; it carries the latter as extensions.requestId. See Error Index for where each service puts it.

How to Resolve

  1. Read the month's state. GET /api/v3/admin/usage/telemetry with grain=month and a from/to range covering the month returns a state for each month that recorded usage, decided by the same rule this refusal applies.
  2. If the month is OPEN, issue the statement after the month has ended and the quiet margin has elapsed. Schedule monthly issuance accordingly rather than at midnight on the first day.
  3. If the month is PROVISIONAL, wait and retry. If it stays PROVISIONAL well past the quiet margin, the cause is on the ingestion side, not in your request: ask the deployment's operator to check that usage events are being ingested and that usage has been recorded since the month ended.
  4. Do not retry in a tight loop. The state changes on the scale of the quiet margin, not of seconds.

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

* restricted content — see higher-tier documentation