Skip to content

Capability Grant Overlap

URI: https://docs.ankatech.co/errors/capability-grant-overlap
HTTP Status: 409 Conflict

When you see this

You asked for a Capability Grant and the actor already holds a live grant that overlaps it. Two grants of one actor overlap when their capabilities intersect and their resources intersect. The refusal does not depend on the Exchange Context, the Constraint Policy or the owner of either grant: an actor's live grants never overlap anywhere in the tenant, so every request the actor makes is authorized by at most one grant. Nothing was written.

The operations that create a grant all answer it the same way:

  • createCapabilityGrant (POST /api/v3/admin/tenants/{tenantId}/capability-grants), a standalone grant;
  • createExchangeGrant (POST /api/v3/admin/exchanges/{id}/grants), a grant owned by a Cryptographic Exchange;
  • createInternalCryptoUseCase, whose grants are written through the same path.

How resources intersect:

  • Basic capabilities (ENCRYPT, DECRYPT, SIGN, VERIFY) intersect on a Key ID both grants name. A wildcard grant (allowWildcardAsset: true) covers every Key ID, so it intersects every basic grant of the actor whose capabilities intersect its own, and every other wildcard grant.
  • Transformation capabilities (REENCRYPT, RESIGN) intersect on an ordered key pair both grants name. REENCRYPT from K1 to K2 overlaps a second REENCRYPT from K1 to K2, but not REENCRYPT from K2 to K1, nor REENCRYPT from K1 to K1: each pair authorizes its own direction only.
  • Disjoint capabilities never overlap. An ENCRYPT grant and a DECRYPT grant on the same key are both admitted.

A grant stops counting once it is no longer live: revoked, consumed, retired with its Exchange or with its Exchange Context.

This is a distinct 409 from Concurrent Modification, which means a stale optimistic-lock version, and a retry after a re-read succeeds. An overlap is refused for the same reason on every retry until a conflicting grant ends or the request is narrowed. A client branches on the type member, never on detail.

Common Causes

  • Adding a grant to a second Exchange for an actor that already holds the same capability on the same key through another Exchange or a standalone grant, in this or another Exchange Context.
  • Creating a kid-named grant for an actor that holds a wildcard grant with an intersecting capability, or a wildcard grant for an actor that holds any intersecting grant.
  • Re-running a provisioning script that created the grant on its first run.

Response Example

{
  "type": "https://docs.ankatech.co/errors/capability-grant-overlap",
  "title": "Capability Grant Overlap",
  "status": 409,
  "detail": "The actor already holds a live Capability Grant whose capabilities and resources intersect this one, in this or another Exchange Context. Revoke the conflicting grant, or narrow the capabilities or keys of this one.",
  "instance": "/api/v3/admin/tenants/7c9e6679-7425-40de-944b-e07fc1f90ae7/capability-grants",
  "timestamp": 1730000000,
  "extensions": {
    "conflictingGrantIds": ["22222222-2222-4222-8222-222222222222"],
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Content-Type: application/problem+json, following RFC 9457 Problem Details. extensions.conflictingGrantIds lists every live grant the request overlaps. They are grants of the actor you named, in your own tenant. The detail is a fixed sentence: it never repeats the capabilities or Key IDs you submitted.

How to Resolve

  1. Do not retry unchanged. Every retry is refused for the same reason.
  2. Read each grant in extensions.conflictingGrantIds (getCapabilityGrant). If one of them already authorizes what you need, use it. A provisioning script can treat this refusal as "already done" when the conflicting grant is the one it meant to create.
  3. If the existing grant must be replaced, end it first. Revoke an Exchange's grant with revokeExchangeGrant (or revoke the Exchange), and revoke a standalone grant with revokeCapabilityGrant. Then repeat the request.
  4. Otherwise narrow the request: drop the intersecting capability, name another key, or name another ordered pair.
  5. To change only the limits a grant enforces, do not create a second grant: re-pin the existing one to another Constraint Policy version with replaceCapabilityGrantPolicyVersion.

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