Skip to content

fix(msteams): FileConsent upload succeeds but FileInfoCard fails — TurnContext proxy revoked #29847

@cwatts-sage

Description

@cwatts-sage

Bug Description

When sending files via FileConsentCard in a Teams DM, the file uploads to OneDrive successfully, but the FileInfoCard (download card) never appears in the chat. The user clicks "Allow", nothing visibly happens, and the file is silently uploaded to OneDrive without any chat confirmation.

Root Cause

In extensions/msteams/src/monitor-handler.ts, the handler.run function handles file consent invokes:

handler.run = async (context: unknown) => {
  const ctx = context as MSTeamsTurnContext;
  if (ctx.activity?.type === "invoke" && ctx.activity?.name === "fileConsent/invoke") {
    await ctx.sendActivity({ type: "invokeResponse", value: { status: 200 } });
    handleFileConsentInvoke(ctx, deps.log).catch(...);
    return;  // handler returns → webhook response sent → TurnContext proxy revoked
  }
};
  1. Invoke response is sent immediately ✅
  2. handleFileConsentInvoke is called (fire-and-forget)
  3. Handler returns → webhook HTTP response completes → TurnContext proxy is revoked by the SDK
  4. Inside handleFileConsentInvoke:
    • uploadToConsentUrl() succeeds (uses plain fetch, no context needed) ✅
    • context.sendActivity(fileInfoCard) fails ❌ — proxy revoked

Error: TypeError: Cannot perform 'get' on a proxy that has been revoked

Expected Behavior

After the user clicks "Allow":

  1. File uploads to OneDrive
  2. FileInfoCard appears in the chat with a download link
  3. User can click to download the file

Actual Behavior

After the user clicks "Allow":

  1. File uploads to OneDrive ✅
  2. FileInfoCard never appears in chat ❌
  3. User sees nothing — appears broken

Attempted Fixes

  1. Await the handler (keep upload synchronous) — context still revoked because invoke response was already sent
  2. setImmediate async — same proxy revocation
  3. adapter.continueConversation(ref, callback)Invalid conversation reference object
  4. adapter.continueConversation(appId, ref, callback) — same invalid ref error

Suggested Fix

The handleFileConsentInvoke function needs access to the proactive messaging dependencies (adapter, appId, conversationStore) so it can send the FileInfoCard via proactive messaging after the upload completes — the same path that send.ts uses for regular proactive messages.

// Pass proactive messaging deps to handler
handleFileConsentInvoke(ctx, deps.log, {
  adapter: deps.adapter,
  appId: deps.appId,
  conversationStore: deps.conversationStore,
}).catch(...);

// Inside handleFileConsentInvoke, after upload:
const ref = await conversationStore.get(conversationId);
await adapter.continueConversation(appId, ref, async (proactiveCtx) => {
  await proactiveCtx.sendActivity({ type: "message", attachments: [fileInfoCard] });
});

Environment

  • OpenClaw: 2026.2.26
  • Plugin: @openclaw/msteams
  • @microsoft/agents-hosting: 1.3.x
  • Bot type: Single Tenant
  • Teams client: Desktop (macOS) and Web
  • Chat type: Personal (1:1 DM)
  • File size: 55 bytes (timing is not the issue — upload takes <1 second)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions