Teams error 403 ForbiddenOperationException: ForbiddenOperationException - app not installed in personal scope
Last verified against Microsoft Learn - Status codes from bot conversational APIs
Agent isn't installed in user's personal scopeWhat error 403 ForbiddenOperationException means
You attempted a proactive one-on-one message to a user who does not have the app installed personally. The status table documents ForbiddenOperationException as "Proactive message is sent by an agent, which isn't installed in a personal scope," retry No, with the action "Before attempting to send another conversation request, install the app in personal scope." The proactive messaging guide adds the precise trigger: creating a conversation by aadObjectId works only in personal scope, and "If the agent isn't installed in a personal scope when sending a proactive message using the aadObjectId, the agent returns a 403 error with ForbiddenOperationException message."
Being installed in a team the user belongs to is not enough for this path - the personal app installation is what creates the 1:1 conversation surface. The standard remedy for notify-everyone scenarios is proactive installation through Microsoft Graph (userteamwork/installedApps), after which your bot receives conversationUpdate/installationUpdate with the real conversation ID to cache.
What it looks like
{
"error": {
"code": "ForbiddenOperationException",
"message": "Agent isn't installed in user's personal scope"
}
}Why it happens
- Proactive send targeted a user by aadObjectId without the app being installed in that user's personal scope.
- The app is installed in a shared team, and the code assumed that covers 1:1 messaging.
- The user uninstalled the personal app; later sends by Entra ID fail with this code.
- A migration changed app IDs, so historical personal installations belong to the old app.
How to fix Teams error 403 ForbiddenOperationException
- 1Check whether the target user has the app installed personally (Graph: list installedApps for the user).
- 2Install the app for the user via Graph (POST /users/{id}/teamwork/installedApps) if your org and app catalog permit it.
- 3Capture the conversation ID from the conversationUpdate that fires on installation and cache it for future sends.
- 4Retry the proactive message only after installation succeeds; the same send then creates or reuses the 1:1 conversation.
How to stop it recurring
Decide at design time how personal conversations come to exist: user-initiated install, admin-driven setup policy, or Graph proactive installation - and implement exactly one. Gate proactive 1:1 sends on a recorded installation rather than optimistically firing and handling 403s. The full flow and its constraints are summarized in proactive messaging constraints.
Official reference: Microsoft Learn - Status codes from bot conversational APIs. See all Teams error codes or the Teams limits and quotas.
Related codes
- 403 MessageWritesBlocked: MessageWritesBlocked - proactive send to a blocking userThread is blocked from message writes.
- 404 ConversationNotFound: ConversationNotFound - conversation missing or deletedConversation not found.
- 403 BotNotInConversationRoster: BotNotInConversationRoster - bot removed from conversationThe agent isn't part of the conversation roster.
Error 403 ForbiddenOperationException - quick answers
What does Teams error 403 ForbiddenOperationException mean?
You attempted a proactive one-on-one message to a user who does not have the app installed personally.
How do I fix Teams error 403 ForbiddenOperationException?
1. Check whether the target user has the app installed personally (Graph: list installedApps for the user). 2. Install the app for the user via Graph (POST /users/{id}/teamwork/installedApps) if your org and app catalog permit it. 3. Capture the conversation ID from the conversationUpdate that fires on installation and cache it for future sends. 4. Retry the proactive message only after installation succeeds; the same send then creates or reuses the 1:1 conversation.
Stop debugging Teams by hand
Connect the channel through Conferbot: tokens, webhooks and retries are handled, failures show as readable status.