Capability Grant Dimensions Conflict
URI: https://docs.ankatech.co/errors/capability-grant-dimensions-conflict
HTTP Status: 409 Conflict
When you see this
You asked for a Capability Grant — directly with createCapabilityGrant, or by activating a Cryptographic Exchange with activateExchange — and a live grant already exists over the same five dimensions: tenant, actor, capabilities, asset kids and Exchange Context. The platform holds at most one live grant per combination, so the second one was refused and nothing was written.
The rule is a partial unique index over live grants only. A revoked grant is outside it, so the same five dimensions can be granted again once the existing grant is revoked. A grant with no Exchange Context participates like any other. The Constraint Policy is not one of the five: two grants that differ only by constraint policy collide.
This is a distinct 409 from Conflict, and the distinction is the point. On these same operations, conflict means a stale optimistic-lock version: re-read the resource and send the request again, and it succeeds. This refusal never succeeds on a retry — the thing you asked for already exists, and it keeps existing until something revokes it. A client must be able to tell the two apart on the type member rather than by string-matching detail, which is prose and may be reworded.
Both operations return the same refusal for the same event, whichever of them created the grant that is already live.
Common Causes
- Activating a second Cryptographic Exchange whose actor, asset key, capability and Exchange Context are the same as those of an Exchange that is still
ACTIVEorSUSPENDED. - Creating a standalone grant over the dimensions of a grant an active Exchange already composes, or of an earlier standalone grant that was never revoked.
- Re-running a provisioning script that created the grant on its first run.
Response Example
{
"type": "https://docs.ankatech.co/errors/capability-grant-dimensions-conflict",
"title": "Capability Grant Dimensions Conflict",
"status": 409,
"detail": "A live Capability Grant already exists for this tenant, actor, capabilities, asset kids and Exchange Context. Revoke that grant, or the Cryptographic Exchange that composes it, or change one of those five dimensions before granting again.",
"instance": "/api/v3/admin/exchanges/7d2f4a10-9c31-4b8e-a5d6-2f11c0b47e93/activate",
"timestamp": 1730000000,
"extensions": {
"requestId": "550e8400-e29b-41d4-a716-446655440000"
}
}
Content-Type: application/problem+json — the response follows RFC 9457 Problem Details. The detail is a fixed sentence: it never repeats the capability, the key identifiers or the actor you submitted.
How to Resolve
- Do not retry unchanged. Every retry is refused for the same reason.
- If the existing grant is the one you want, use it: it already authorizes the combination you asked for. A provisioning script can treat this refusal as "already done".
- If it must be replaced, revoke it first. A grant composed by a Cryptographic Exchange is revoked by revoking that Exchange, which retires its grant in the same transaction; a standalone grant is revoked with
deleteCapabilityGrant. Then repeat the request. - Otherwise change one of the five dimensions — a different capability, key or Exchange Context. Changing only the Constraint Policy does not avoid the collision.
For full schema definitions, examples, and interactive testing, see the Developer Hub Reference.