When a session can't find a connected account
A session only sees connected accounts that match its project and its user_id. An account can show as active in the dashboard and still be invisible to your session if it was created under a different user ID or auth config.
How the pieces fit
- Project. Your API key picks the project. Auth configs, connected accounts, and sessions never cross projects.
- Auth config. How a toolkit authenticates: Composio managed auth or your own credentials. See Managed vs custom auth.
- Connected account. One user's credentials for one auth config. Each account stores the
user_idit was created for. - Session. Created for one
user_id. At execution time it picks anACTIVEaccount that belongs to that user, unless you pin one withconnectedAccounts.
Use your application's own stable user ID everywhere: when you create sessions and when you connect accounts. See userID best practices.
Find the user ID that owns the account
Look up the account by its ID (ca_..., shown in the dashboard) and read its user_id:
account = composio.connected_accounts.get("ca_123")
print(account.user_id, account.status, account.auth_config.id)If the user_id isn't the one your session uses, the session won't find the account. This happens most often with accounts connected outside your app, such as from the dashboard or a developer tool. For example, composio dev init writes a playground test user (pg-test-<your member ID>) to COMPOSIO_TEST_USER_ID, which is not one of your application's users.
You can't change the user_id of an existing connected account. Reconnect it under the right user instead.
Check the rest of the match
If the user ID matches and the session still can't use the account, check these in order:
- Status. The account must be
ACTIVEand not disabled.INITIATEDmeans the user never finished the flow.EXPIREDmeans it needs a new grant. See connection status. - Toolkit restrictions. If the session sets
toolkits, the toolkit must be allowed. Toolkit restrictions apply before account lookup. - Auth config. If the session passes
authConfigsfor the toolkit, the account must belong to that auth config. - Tool Router flag. Auth configs that sessions create are enabled for Tool Router automatically. If you created the auth config yourself, in the dashboard or the API, set
is_enabled_for_tool_routertotrueso sessions can match its accounts byuser_id. - Pinned account. If the session passes
connectedAccountsfor the toolkit, it uses exactly that account and never falls back to another one. Update the session or create a new one to change it.
Enable the Tool Router flag on an auth config you created:
composio.auth_configs.update(
"ac_your_config",
options={"type": "custom", "is_enabled_for_tool_router": True},
)Reconnect under the right user
Create a session for your application's user ID, then authorize the toolkit from that session. The new connected account belongs to that user, so this session and later sessions for the same user can use it. Pass authConfigs if the toolkit uses your own auth config.
session = composio.create(
user_id="user_123",
auth_configs={"gmail": "ac_your_config"},
)
connection_request = session.authorize("gmail")
print(connection_request.redirect_url) # Send the user here
connection_request.wait_for_connection(60)
# Confirm the session sees the account
for toolkit in session.toolkits(is_connected=True).items:
account = toolkit.connection and toolkit.connection.connected_account
print(toolkit.slug, account.id if account else None)Only send the Connect Link to the person who owns that user ID. Whoever completes the flow decides which external account gets attached to user_123.
Once the new account is active, delete or disable the old one under the wrong user ID if nobody needs it. See Connected accounts.