paperclipai/paperclip · error · ToolGatewayHttpError
ambiguous_personal_grant
ambiguous_personal_grant
Error message
More than one delegated personal authorization matches this autonomous run
What it means
The tool gateway resolves a user-scope ('personal') credential grant for an autonomous run by querying connection grant delegations for the session's agent. When more than one active delegated personal grant matches the same connection and agent, the gateway cannot pick one deterministically and throws this 409 instead of guessing.
Solutions
- Query connectionGrantDelegations for the agentId/connectionId and revoke or delete all but one active delegation
- Set the older duplicate delegation's status to revoked/inactive via the grants admin API or UI
- Re-run the tool call once a single active delegated personal grant remains
Example fix
// before: duplicate delegations
await db.delete(connectionGrantDelegations).where(and(eq(connectionGrantDelegations.agentId, agentId), eq(connectionGrantDelegations.grantId, staleGrantId)));
// after: keep exactly one active delegation
const keep = delegated[0];
await db.update(connectionGrantDelegations).set({ status: 'revoked' }).where(and(eq(connectionGrantDelegations.agentId, agentId), ne(connectionGrantDelegations.grantId, keep.grantId))); Defensive patterns
Strategy: validation
Validate before calling
const delegated = await db.select().from(connectionGrantDelegations).where(and(eq(connectionGrantDelegations.agentId, agentId), eq(connectionGrantDelegations.grantId, grantId)));
if (delegated.filter(d => d.status === 'active').length > 1) throw new Error('De-duplicate delegations before running'); Prevention
- Revoke existing delegations before re-delegating a connection to the same agent
- Add a unique constraint or upsert on (agentId, connectionId) for active delegations
- Audit delegations after company/agent reconfiguration
When it happens
Trigger: An agent session with agentId set requests a tool bound to a connection with kind 'user' credential policy, and the DB contains >=2 rows in connection_grant_delegations joining to active user-kind connection_grants for that (connectionId, agentId) pair.
Common situations: Re-hiring or re-delegating the same personal connection to the same agent without revoking the previous delegation; a bug or manual DB edit duplicating delegations; company merges that copy grant rows.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- github_identity_unavailable
- grant_audience_denied
- organization_authorization_required
- A different semantic result was already committed
- access.reasonCode
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/59488ddbff34fadf.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:4554
and(
eq(connectionGrants.id, connectionGrantDelegations.grantId),
eq(
connectionGrants.companyId,
connectionGrantDelegations.companyId,
),
),
)
.where(
and(
eq(connectionGrantDelegations.companyId, connection.companyId),
eq(connectionGrantDelegations.agentId, session.agentId),
eq(connectionGrants.connectionId, connection.id),
eq(connectionGrants.kind, "user"),
eq(connectionGrants.status, "active"),
),
);
if (delegated.length > 1) {
throw new ToolGatewayHttpError(
409,
"More than one delegated personal authorization matches this autonomous run",
"ambiguous_personal_grant",
{
connectionId: connection.id,
agentId: session.agentId,
},
);
}
userGrant = delegated[0]?.grant;
if (userGrant?.subjectUserId) {
const [membership] = await db
.select({ id: companyMemberships.id })
.from(companyMemberships)
.where(
and(
eq(companyMemberships.companyId, connection.companyId),
eq(companyMemberships.principalType, "user"),View on GitHub (pinned to 3f1d897a7c)