Skip to content
Scalekit Docs
Talk to an Engineer Dashboard

Troubleshoot connection and OAuth errors

Fix AgentKit connection errors: account statuses, failed_to_exchange_token, session_not_found, redirect_uri_mismatch, and Google, Microsoft or Slack consent.

When a user can’t connect an app, or a connected account stops working, the cause is almost always one of three things: the account’s status, an error from Scalekit’s connection error page, or a rule the provider enforces on your OAuth app. Check the status first, then find the error text below. Each error is its own heading, so you can link straight to it.

For errors from tool calls, the API proxy or a Virtual MCP server, see the Common problems on Use built-in tools, Call any API and Virtual MCP servers.

The connected account’s status tells you whether the user never finished authorizing, still needs identity verification, has an expired token, or disconnected.

account = actions.get_connected_account(
identifier="user_123",
connection_name="github-connect",
).connected_account
print(account.status) # ACTIVE, EXPIRED, PENDING_AUTH, PENDING_VERIFICATION or DISCONNECTED
# Scopes the user granted (OAuth connections only)
print((account.authorization_details or {}).get("oauth_token", {}).get("scopes"))

If the status is ACTIVE but a tool call fails, run a read-only tool such as github_user_get_authenticated. If that works, the connection is fine and the problem is in the call: see Use built-in tools.

To learn about status changes without polling, subscribe to the connected_account.status_updated and connected_account.token_refresh_failed webhooks. See Listen for account events.

StatusMeaningFix
ACTIVECredentials are validNothing to fix. Tool calls work.
PENDING_AUTHThe user hasn’t finished authorizingSend an authorization link
PENDING_VERIFICATIONAuthorization succeeded, identity verification hasn’tFinish user verification
EXPIREDThe token expired or was revoked, and Scalekit couldn’t refresh itSend a new authorization link
DISCONNECTEDThe account was disconnected in ScalekitSend a new authorization link

The user hasn’t finished authorizing, or you started re-authorization and they haven’t completed it. Create an authorization link and send it through your app, for example as an in-app prompt or on a settings page.

if account.status == "PENDING_AUTH":
link = actions.get_authorization_link(
connection_name="github-connect",
identifier="user_123",
)
print(link.link)

The status changes to ACTIVE when the user finishes, or to PENDING_VERIFICATION if your environment verifies users.

The user authorized the app, but Scalekit is waiting for your app to confirm the user’s identity before it activates the account. Complete the verification step described in Verify user identity. After verification succeeds, the status is ACTIVE.

The access token expired and Scalekit couldn’t refresh it, for example because the user removed your app’s access at the provider, such as in their Google Account’s third-party connections. Scalekit refreshes tokens on its own, so there’s no refresh call to make: send the user a new authorization link, as for PENDING_AUTH.

If the account expires again soon after every re-authorization, the connection never received a refresh token. Providers issue one only when the connection asks for offline access. Add the provider’s offline-access scope, such as offline_access, in Configure scopes, then have the user connect again. Common causes lists the other reasons accounts expire.

The account was disconnected in Scalekit, from the dashboard or by a disconnect call from your app. Its credentials are cleared, so only re-authorization fixes it. Send a new authorization link, and until the user reconnects, show the state in your UI and stop scheduling tool calls for that account.

When authorization fails, Scalekit sends the user to its connection error page. The page shows a title, and its Debug info panel shows the error code, the error_description and an Auth Request ID. Find the title or the code below.

Authorization failed (failed_to_exchange_token)

Section titled “Authorization failed (failed_to_exchange_token)”

The user approved access, but Scalekit couldn’t finish the connection. Read the error_description to find which step failed:

  • The provider rejected the token exchange. The description holds the provider’s error, such as invalid_client or invalid_grant. Check the client ID and secret on the connection: see Invalid client or client authentication failed. An authorization code is valid once and briefly, so a user who waited a long time on the consent screen should start again.

The page also suggests organization-level causes. The user’s admin may have blocked your app with an access policy, the app may lack permission in the organization’s settings, or the user’s account may not have the rights to authorize it. The provider errors below cover how Google, Microsoft and Slack report these.

Session expired or not available (session_not_found)

Section titled “Session expired or not available (session_not_found)”

Your environment’s user verification mode is Scalekit users only, and the person authorizing isn’t signed in to the Scalekit dashboard. Scalekit uses the dashboard session to confirm who the user is, so without one it can’t activate the account.

  • If the user is on your team, have them sign in to the Scalekit dashboard in the same browser and start the flow again.
  • If the user is a customer, they don’t have a Scalekit login. Switch to Custom user verifier in AgentKit > Settings > User Verification, and verify users in your own app. See Verify user identity.

This isn’t a timeout: retrying without signing in fails the same way.

The flow was refused. Two things cause it:

  • The user declined consent at the provider, or the provider denied the request. The provider sends access_denied back and Scalekit shows it with this title. Offer the user a way to start again.
  • Scalekit’s identity check failed in Scalekit users only mode. The user is signed in to a different Scalekit workspace, or, for a flow started from the dashboard’s playground, as a different user from the one who started it. Sign in with the expected account and start again.

The request reached Scalekit without a required parameter, or with one it couldn’t read, such as a missing auth_request_id or state. This happens when a link is truncated, edited or reused. Create a new authorization link and use it unchanged. If the provider returned invalid_request, the authorization request didn’t meet its rules: check the connection’s scopes and settings.

An unexpected error, in Scalekit or at the provider. Start the flow again after a few minutes, and check the Scalekit status page and the provider’s status page. If it persists, contact support with the Auth Request ID.

Two error_description values point to a specific step:

  • user_verify_url not configured for verification redirect. Your environment uses Custom user verifier, but the authorization link was created without a user_verify_url. Pass one when you create the link, or switch modes. See Verify user identity.
  • Error executing post auth hooks. Scalekit stored the tokens but a step after authorization failed. Start the flow again. If it fails again, contact support with the Auth Request ID.

Scalekit passes the provider’s own OAuth error through to the page, where it shows as Unable to complete connection. The codes are defined in RFC 6749:

CodeMeaningWhat to do
unauthorized_clientThe provider doesn’t allow this OAuth app to use this flowCheck the app’s settings in the provider’s console
invalid_scopeA requested scope is unknown or not allowed for this appFix the scopes on the connection, then retry
unsupported_response_typeThe provider doesn’t support the authorization code flow for this appCheck the app type in the provider’s console
temporarily_unavailableThe provider is overloaded or down for maintenanceRetry after a few minutes

These come from the OAuth app a connection uses, whether it’s Scalekit’s or one you registered.

The redirect URI registered in the provider’s OAuth app doesn’t match the one Scalekit sends. Providers require an exact match.

  1. In the Scalekit dashboard, open AgentKit > Connections and select the connection.
  2. Copy the Redirect URI.
  3. In the provider’s developer console, paste it into the OAuth app’s allowed redirect URIs.
  4. Save, and start the connection flow again.

Most mismatches are a trailing slash (/callback/ and /callback), http instead of https, or a missing port number in local development.

Invalid client or client authentication failed

Section titled “Invalid client or client authentication failed”

The client ID or secret on the connection doesn’t match the provider’s OAuth app. Providers report it as invalid_client, inside a failed_to_exchange_token error.

  1. Open AgentKit > Connections and select the connection.
  2. Compare the Client ID and Client Secret with the OAuth app in the provider’s console.
  3. If the secret was rotated or expired, create a new one in the provider’s console and paste it into the connection.
  4. Start the connection flow again.

Scalekit checks the OAuth state parameter to protect against cross-site request forgery, and fails the flow with invalid_state when it’s missing or doesn’t match. The connection error page shows it as Unable to complete connection. Finish the flow in the same browser it started in, allow cookies, and start again from a fresh authorization link rather than a bookmarked or back-button page.

Authorization succeeds but tools fail on a missing scope

Section titled “Authorization succeeds but tools fail on a missing scope”

The user’s token doesn’t include a scope a tool needs. The app returns an error such as Slack’s missing_scope, or a 403. Add the scope in Configure scopes, then have the user authorize again: existing tokens don’t gain new scopes.

The connection works but access tokens come back empty

Section titled “The connection works but access tokens come back empty”

A connected account has an ID, such as ca_..., but its access and refresh token fields are empty. That’s expected: API responses don’t include provider tokens by default, which keeps them out of your app. Call tools with execute_tool or the API proxy, which add the user’s token for you. To read the tokens themselves, contact support to enable it.

Each provider sets its own rules for OAuth apps. These are the common ones, with links to the provider’s documentation.

It works for your account but fails for your customers

Section titled “It works for your account but fails for your customers”

A provider OAuth app often starts in a development or testing state that only its creator, or a short list of test users, can authorize. The connection works while you test it with your own account, and fails when a customer connects. Listing tools also works for you, because your own account already authorized the app. This applies to OAuth apps you registered and to connections that use Scalekit’s shared credentials.

To fix it, finish the provider’s requirements for external use, publish the app, and connect again from an account outside your organization. Publish your own OAuth apps in the launch checklist lists the steps. For example:

  • Google limits apps in the Testing publishing status to 100 test users that you list on the OAuth consent screen. Publish the app to production, and complete verification if it requests sensitive or restricted scopes. See Google’s publishing status guide.
  • Airtable returns “This OAuth application cannot be used outside of development” until the integration has a privacy policy URL, a terms of service URL and a support email. See Airtable’s OAuth integration guide.
  • ZoomInfo offers partner apps for serving customers across organizations. Partner apps go through ZoomInfo’s review before customers can install them. See ZoomInfo partner apps.

Google: unverified app screen or admin_policy_enforced

Section titled “Google: unverified app screen or admin_policy_enforced”

Google shows an unverified app screen when an app that hasn’t completed verification requests sensitive or restricted scopes, and caps such an app at 100 new users. Complete Google’s app verification, or request fewer sensitive scopes.

admin_policy_enforced means the user’s Google Workspace administrator doesn’t allow the app to access one or more requested scopes. The administrator can mark the app as trusted by its OAuth client ID in the Admin console’s API controls. See Google’s OAuth error reference.

Microsoft: AADSTS65001 or “Need admin approval”

Section titled “Microsoft: AADSTS65001 or “Need admin approval””

AADSTS65001 means the user or an administrator hasn’t consented to the permissions the app requests. When the tenant doesn’t allow users to consent, the user sees Need admin approval, and the error can be AADSTS90094 (administrator consent is required).

  1. Open the app registration in the Microsoft Entra admin center.
  2. Check that its API permissions match the connection’s scopes.
  3. Have a tenant administrator select Grant admin consent.
  4. Start the connection flow again.

See Microsoft’s consent troubleshooting guide and error code reference.

The account the user signed in with doesn’t exist in the tenant the app expects, for example a personal account or an account from another organization signing in to a single-tenant app. Have the user sign in with their work or school account in that tenant, have an administrator add them as an external user, or make the app registration multi-tenant. See Microsoft’s error code reference.

Slack: the workspace requires app approval

Section titled “Slack: the workspace requires app approval”

When a Slack workspace only allows pre-approved apps, a member who tries to install your app submits a request instead, and the connection can’t finish until an administrator approves it. Ask a workspace administrator to approve the app, or test in a workspace where you manage app settings. See Slack’s app approval guide.

The provider rejected calls because of its rate limit or quota, usually with a 429. Retry with exponential backoff, and cache read results where you can. With your own OAuth credentials, your app gets its own quota at providers that set quotas per OAuth app.

Open AgentKit > Connected Accounts in the Scalekit dashboard to see the account’s status and tool call logs. When you contact support@scalekit.com, include:

  • The Auth Request ID from the connection error page, if there was one
  • The connected account ID, or the user’s identifier and the connection name
  • The full error text and when it happened
  • The steps that reproduce it

API reference

The endpoints this page's code calls, with every field and the SDK method for each: