{"record":{"id":"b4f6a2234b41b0b7","repo":"ComposioHQ/composio","slug":"error-message-upstream-badrequesterror-acl-onl","errorCode":null,"errorMessage":"${error.message (upstream BadRequestError: ACL only allowed for shared connections)}","messagePattern":"\\$\\{error\\.message \\(upstream BadRequestError: ACL only allowed for shared connections\\)\\}","errorType":"exception","errorClass":"ComposioAclOnlyForSharedError","httpStatus":400,"severity":"error","filePath":"ts/packages/core/src/models/ConnectedAccounts.ts","lineNumber":446,"sourceCode":"        response.connected_account_id,\n        ConnectedAccountStatuses.INITIATED,\n        response.redirect_url\n      );\n      return connectionRequest;\n    } catch (error) {\n      // Caller-initiated cancellation must surface as the typed error,\n      // not get remapped to ComposioFailedToCreateConnectedAccountLink below.\n      if (error instanceof ComposioRequestCancelledError) {\n        throw error;\n      }\n      // The server rejects ACL on PRIVATE connections — surface that as a\n      // typed error so callers can `instanceof` instead of grepping messages.\n      if (\n        error instanceof BadRequestError &&\n        typeof error.message === 'string' &&\n        error.message.includes(ACL_ONLY_FOR_SHARED_ERROR_FRAGMENT)\n      ) {\n        throw new ComposioAclOnlyForSharedError(error.message, { cause: error });\n      }\n      throw new ComposioFailedToCreateConnectedAccountLink(\n        'Failed to create connected account link',\n        {\n          cause: error,\n        }\n      );\n    }\n  }\n\n  /**\n   * Waits for a connection request to complete and become active.\n   *\n   * This method continuously polls the Composio API to check the status of a connection\n   * until it either becomes active, enters a terminal error state, or times out.\n   *\n   * @param {string} connectedAccountId - The ID of the connected account to wait for\n   * @param {number} [timeout=60000] - Maximum time to wait in milliseconds (default: 60 seconds)","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/core/src/models/ConnectedAccounts.ts#L428-L464","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait c.connectedAccounts.link('github', { user:'u1', acl: teamAcl });\n// after\nawait c.connectedAccounts.link('github', { user:'u1' }); // acl only on shared connections","handlingStrategy":"try-catch","validationCode":"if (options.acl && !isSharedConnection) delete options.acl; // only send acl for shared connections","typeGuard":"const isAclOnlyForShared = (e: unknown): boolean => e instanceof ComposioAclOnlyForSharedError;","tryCatchPattern":"try { await ca.link(id, opts); } catch (e) { if (e instanceof ComposioAclOnlyForSharedError) { const { acl, ...rest } = opts; await ca.link(id, rest); } }","preventionTips":["Never attach acl to personal connections","Feature-flag acl config on shared connections only"],"tags":["acl","connected-accounts","bad-request","permissions"],"backgroundTag":"acl-not-allowed","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}