Skip to content

fix(gateway): surface grants 409 stale-version conflict as typed error instead of id-less success - #183

Open
maciejwitowski wants to merge 1 commit into
mainfrom
maciej/grant-409-typed-conflict
Open

fix(gateway): surface grants 409 stale-version conflict as typed error instead of id-less success#183
maciejwitowski wants to merge 1 commit into
mainfrom
maciej/grant-409-typed-conflict

Conversation

@maciejwitowski

Copy link
Copy Markdown
Collaborator

Problem

createGatewayClient().createGrant treats every POST /v1/grants 409 as idempotent success. But the gateway has two distinct 409s:

  • Idempotent replay — body echoes the existing grant id → success is correct.
  • Stale grantVersion — body is {success:false, error, currentGrantVersion} with no grant id → the registration did not apply, and the SDK returned {grantId: undefined}, silently discarding the currentGrantVersion rebase hint.

Downstream impact (traced live on Moksha): the id-less "success" propagates through personal-server-ts (201 with no grantId) into the unity-surfaces DCR client, which terminally fails external-consumer DCRs with the misleading missing_external_completion_routing ("Personal Server routing is not ready yet") — routing was fine. This breaks the one-go builder flow (connect source + grant in one pass). Web-side mitigation: vana-com/unity-surfaces#744.

Change

  • createGrant keeps idempotent-success only when the 409 body carries a grant id.
  • Otherwise it throws the new exported GatewayGrantVersionConflictError (name, status: 409, currentGrantVersion) with the gateway's error message, so callers can re-sign at currentGrantVersion + 1 and retry.
  • Exported from both browser and server entrypoints.

Compatibility

Behavior changes only for the stale-version case, which previously produced a broken success (grantId: undefined) that no caller could act on. personal-server-ts should adopt conflict handling (auto-rebase retry) in the same release that bumps past this version — follow-up PR incoming.

Tests

  • New: grants 409 with {currentGrantVersion, no id} → rejects with typed error carrying the hint.
  • Existing idempotent-replay test (409 with id) unchanged and passing.
  • Full package suite: 847/847 green.

🤖 Generated with Claude Code

…bricating id-less success

A grants 409 without a grant id is a stale-grantVersion conflict — the
registration did NOT apply. Returning `{grantId: undefined}` made callers
treat it as success and lose the gateway's `currentGrantVersion` rebase
hint; downstream this terminally failed external-consumer DCRs with the
misleading `missing_external_completion_routing`.

createGrant now keeps the idempotent-replay behavior when the 409 body
carries a grant id, and otherwise throws the exported
`GatewayGrantVersionConflictError` (status 409, `currentGrantVersion`)
so callers can re-sign at currentGrantVersion+1 and retry.

Note for consumers: personal-server-ts should adopt conflict handling
(auto-rebase retry) in the same release that bumps past this version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
vana-console Ignored Ignored Jul 11, 2026 10:14pm
vana-rbac-auditor Ignored Ignored Jul 11, 2026 10:14pm
vana-vibes-demo Ignored Ignored Jul 11, 2026 10:14pm

Request Review

@github-actions

Copy link
Copy Markdown

No blocking findings. The change correctly distinguishes idempotent 409s from stale-version conflicts and exports the typed error from browser/node entrypoints.

Minor test improvement: assert instanceof GatewayGrantVersionConflictError and the gateway error message, not only matching object fields.

Tests could not run because dependencies (vitest) are not installed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant