ComposioHQ/composio · error · ComposioAclOnlyForSharedError
${error.message (upstream BadRequestError: ACL only allowed
Error message
${error.message (upstream BadRequestError: ACL only allowed for shared connections)} What it means
Wrapped ComposioAclOnlyForSharedError: the backend returned BadRequestError containing the 'ACL only allowed for shared connections' fragment. The connection request set acl/permissions on a non-shared connection, which the API rejects.
Source
Thrown at ts/packages/core/src/models/ConnectedAccounts.ts:446
response.connected_account_id,
ConnectedAccountStatuses.INITIATED,
response.redirect_url
);
return connectionRequest;
} catch (error) {
// Caller-initiated cancellation must surface as the typed error,
// not get remapped to ComposioFailedToCreateConnectedAccountLink below.
if (error instanceof ComposioRequestCancelledError) {
throw error;
}
// The server rejects ACL on PRIVATE connections — surface that as a
// typed error so callers can `instanceof` instead of grepping messages.
if (
error instanceof BadRequestError &&
typeof error.message === 'string' &&
error.message.includes(ACL_ONLY_FOR_SHARED_ERROR_FRAGMENT)
) {
throw new ComposioAclOnlyForSharedError(error.message, { cause: error });
}
throw new ComposioFailedToCreateConnectedAccountLink(
'Failed to create connected account link',
{
cause: error,
}
);
}
}
/**
* Waits for a connection request to complete and become active.
*
* This method continuously polls the Composio API to check the status of a connection
* until it either becomes active, enters a terminal error state, or times out.
*
* @param {string} connectedAccountId - The ID of the connected account to wait for
* @param {number} [timeout=60000] - Maximum time to wait in milliseconds (default: 60 seconds)View on GitHub (pinned to 64b1b85502)
Solutions
- Remove acl settings for personal (non-shared) connections
- Mark the connection as shared if ACLs are required
- Catch ComposioAclOnlyForSharedError and retry without the acl option
Example fix
// before
await c.connectedAccounts.link('github', { user:'u1', acl: teamAcl });
// after
await c.connectedAccounts.link('github', { user:'u1' }); // acl only on shared connections Defensive patterns
Strategy: try-catch
Validate before calling
if (options.acl && !isSharedConnection) delete options.acl; // only send acl for shared connections
Type guard
const isAclOnlyForShared = (e: unknown): boolean => e instanceof ComposioAclOnlyForSharedError;
Try / catch
try { await ca.link(id, opts); } catch (e) { if (e instanceof ComposioAclOnlyForSharedError) { const { acl, ...rest } = opts; await ca.link(id, rest); } } Prevention
- Never attach acl to personal connections
- Feature-flag acl config on shared connections only
When it happens
Trigger: Calling link() with an acl/permission option while the connection is not a shared (team-level) connection; the backend BadRequest is rethrown as a typed error so callers can instanceof-check it.
Common situations: Migrating from team shared-connection code to per-user connections but leaving ACL config in place; enabling ACL fields conditionally so they leak into personal connections.
Related errors
- Failed to parse connected account ACL update params
- ${error.message (upstream BadRequestError: ACL only allowed
- File not readable: {file}. Please check the file permissions
- HTTP ${response.status} ${response.statusText}
- Forbidden
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/b4f6a2234b41b0b7.
Report an issue: GitHub.