Format grant 409: exists, self, or workspace_required

A 409 on POST .../grants is format_grant_exists, format_grant_self or format_workspace_required. Each has its own fix, and none is a retry.

4 min readSume
All posts

A 409 from POST /v1/formats/{handle}/{slug}/grants means the pair is already related or cannot be related. The error.code tells you which of three cases it is: format_grant_exists, format_grant_self, or format_workspace_required. Retrying the same request never changes the outcome.

The three codes

Grant create 409 codes, from the OpenAPI response description (read 2026-10-05)
error.codeMeaningFix
format_grant_existsThat workspace already holds a pending or accepted grant.Revoke it, then invite again; or PATCH the role if only the role must change.
format_grant_selfThe workspace you named already owns the Format.Name the partner workspace, not your own.
format_workspace_requiredThe Format is not owned by a team workspace. Only team Formats can be shared.Move the Format into a team workspace, then share it.

Exists: re-invite versus change role

The most common one is format_grant_exists. It fires for a pending grant as well as an accepted one, so an invite your partner never answered blocks a second invite. If the goal is to give an existing partner write access, do not revoke and re-invite, because that resets the accept step. Use the role update call on the same grant instead.

If the goal really is a fresh invite, for example the partner lost the grant id, revoke first and then create again.

# change the role in place instead of re-inviting
curl -sS -X PATCH "https://api.sume.com/v1/formats/acme/product-promo/grants/kiwi" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"role":"write"}'

Self: usually a handle mix-up

format_grant_self appears when the handle you put in workspace resolves to the workspace that owns the Format. It most often comes from a script that reuses the owner handle for both the path and the body.

Workspace required: personal Formats

Sharing is workspace to workspace, so the Format itself must belong to a team workspace. A Format that sits under a personal account cannot be granted to anyone, and the API says so with this code rather than a generic 400.

Reading the error in a script

Branch on error.code, never on the message text, because the message is for humans and may be reworded. A small switch is enough: on format_grant_exists, fetch the roster with GET .../grants and decide between a role PATCH and a revoke; on format_grant_self, log a configuration bug; on format_workspace_required, stop and alert a person, since no API call fixes it.

Every error body also carries a request_id. Keep it in your log line, so a support question about a particular rejection can be answered from the one identifier instead of from timestamps.

One practical habit for onboarding scripts: list before you create. A GET on the grants path costs one call and tells you whether the invite already exists, which avoids the conflict and also shows you the accepted state of earlier invites.

Limits

These three are validation conflicts, so the response carries retryable: false and a fix_input next action in the OpenAPI example. Do not put them behind a backoff loop.

They are different from the 404 workspace_not_found and format_not_found cases, which say the invitee or the Format could not be resolved at all.

Sources

Related posts

More in Formats

All Formats posts

Written by Sume