{"record":{"id":"82465fe9e73bb35c","repo":"ComposioHQ/composio","slug":"failed-to-create-connected-account-link","errorCode":null,"errorMessage":"Failed to create connected account link","messagePattern":"Failed to create connected account link","errorType":"exception","errorClass":"ComposioFailedToCreateConnectedAccountLink","httpStatus":null,"severity":"error","filePath":"ts/packages/core/src/models/ConnectedAccounts.ts","lineNumber":448,"sourceCode":"        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)\n   * @returns {Promise<ConnectedAccountRetrieveResponse>} The finalized connected account data\n   * @throws {ComposioConnectedAccountNotFoundError} If the connected account cannot be found","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/core/src/models/ConnectedAccounts.ts#L430-L466","documentation":"Generic ComposioFailedToCreateConnectedAccountLink: the underlying API call to create the connection link failed for any reason other than the ACL-only-for-shared case. The original error is attached as cause.","triggerScenarios":"Any backend failure during link() — invalid authConfigId, expired/invalid API key, malformed redirectUrl, network errors, or backend 4xx/5xx responses not matching the ACL fragment.","commonSituations":"Wrong API base URL or key in dev environments, typo'd auth config slug, redirect URL not allowlisted on the backend.","solutions":["Inspect error.cause for the HTTP status/body","Verify the authConfigId exists (composio.authConfigs.get)","Check the redirectUrl is a valid, allowlisted https URL","Verify API key and environment (api.composio.com vs staging) match"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"await composio.authConfigs.get({ toolkits: [authConfigId] }); // confirm config exists before linking","typeGuard":"const isLinkFailed = (e: unknown): boolean => e instanceof ComposioFailedToCreateConnectedAccountLink;","tryCatchPattern":"try { await ca.link(id, opts); } catch (e) { if (e instanceof ComposioFailedToCreateConnectedAccountLink) { log(e.cause); /* inspect HTTP error, fix config, retry once */ } }","preventionTips":["Validate authConfigId exists first","Use https redirect URLs allowlisted in the dashboard"],"tags":["connected-accounts","api-error","oauth","link"],"backgroundTag":"connection-link-failed","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}