Skip to content

fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility#41838

Merged
onutc merged 4 commits intoopenclaw:mainfrom
BradGroux:fix/msteams-team-key-format
Mar 10, 2026
Merged

fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility#41838
onutc merged 4 commits intoopenclaw:mainfrom
BradGroux:fix/msteams-team-key-format

Conversation

@BradGroux
Copy link
Copy Markdown
Contributor

@BradGroux BradGroux commented Mar 10, 2026

Summary

When OpenClaw starts up and resolves the MS Teams channel allowlist, it queries the Microsoft Graph API for team info and stores the Graph API group GUID (e.g. fa101332-cf00-431b-b0ea-f701a85fde81) as the team key in its allowlist config. At runtime, the Bot Framework sends activity.channelData.team.id as the General channel's conversation ID (e.g. 19:[email protected]) — a completely different format. The two keys never match, so every inbound channel message is silently dropped regardless of config. This PR fixes the mismatch by resolving the General channel's conversation ID during startup and storing that as the team key instead.

Problem

Observed behavior

After configuring a Teams channel in OpenClaw, channel messages are never processed. No errors appear — messages just vanish. The configured team matches by display name at startup, the resolved: true response looks correct, but at runtime nothing gets through.

Diagnostic evidence

Patching the message handler to log activity.channelData:

{
  "team": {
    "id": "19:[email protected]",
    "name": "Digital Meld"
  },
  "channel": {
    "id": "19:[email protected]"
  }
}

The startup resolver stored fa101332-cf00-431b-b0ea-f701a85fde81 (Graph GUID). The runtime key is 19:[email protected] (General channel conversation ID). These never match.

A workaround confirmed the root cause: manually replacing the Graph GUID in config with the General channel's conversation ID caused messages to flow correctly.

Root Cause

The Microsoft Graph API /teams endpoint returns groups by their AAD group GUID (e.g. fa101332-cf00-431b-b0ea-f701a85fde81). This is what listTeamsByName returns as team.id.

The Bot Framework, however, identifies the team context of a channel message using the General channel's conversation ID — the 19:…@thread.tacv2 format used for all Teams conversations. These are two different identifiers for the same team, and there is no documented 1:1 mapping without calling the channels API.

resolveMSTeamsChannelAllowlist was using the Graph GUID directly as teamId in the resolved config entry. At runtime, the allowlist check compares channelData.team.id (conversation ID format) against the stored teamId (GUID format) — a comparison that can never succeed.

Fix

In resolveMSTeamsChannelAllowlist's mapInput callback, after obtaining graphTeamId (the Graph GUID), the fix:

  1. Always calls listChannelsForTeam(token, graphTeamId) — necessary to find the General channel regardless of whether a specific channel was requested.
  2. Finds the General channel by displayName === "general" (case-insensitive).
  3. Uses the General channel's conversation ID as teamId — this matches what Bot Framework sends as channelData.team.id at runtime.
  4. Falls back to the Graph GUID if the General channel is not found (renamed or deleted edge case) so resolution still succeeds rather than silently breaking.
  5. Wraps the channel fetch in try/catch — if listChannelsForTeam throws (rate limit, network error), falls back to the Graph GUID rather than failing the entire resolution. This preserves the pre-fix behavior where team-only entries never called the channels API.
  6. Reuses the channel list when a specific channel is also configured, avoiding a redundant second API call.
// Before
const teamId = teamMatch.id?.trim(); // Graph GUID — wrong format at runtime

// After
const graphTeamId = teamMatch.id?.trim();
let teamChannels = [];
try {
  teamChannels = await listChannelsForTeam(token, graphTeamId);
} catch {
  // API failure — fall back to Graph GUID as team key
}
const generalChannel = teamChannels.find(
  (ch) => ch.displayName?.toLowerCase() === "general",
);
const teamId = generalChannel?.id ?? graphTeamId; // Conversation ID — matches Bot Framework

Testing

Unit tests (extensions/msteams/src/resolve-allowlist.test.ts):

  • Updated existing test "resolves team/channel by team name + channel display name" to assert that teamId is now the General channel's conversation ID, not the Graph GUID.
  • Added "uses General channel conversation ID as team key for team-only entry" — verifies team-only resolution stores the correct key.
  • Added "falls back to Graph GUID when General channel not found" — verifies the edge case gracefully degrades.
  • Added "falls back to Graph GUID when listChannelsForTeam throws" — verifies API failures don't break resolution.

All 6 tests pass:

✓ extensions/msteams/src/resolve-allowlist.test.ts (6 tests) 3ms

Manual validation: Confirmed the workaround (manually setting the General channel conversation ID as config key) makes messages flow correctly. This fix automates that resolution at startup.

Breaking Changes

None. This is fully backward compatible:

  • Existing configs using a conversation ID as the team key (the manual workaround) continue to work — if the input matches the GUID regex (/^[0-9a-fA-F-]{16,}$/), it goes through listChannelsForTeam against that ID, which will still resolve correctly.
  • Configs using a team display name now automatically resolve to the correct conversation ID key.
  • No changes to the config file format or external-facing API.

Secondary Issue (noted, not fixed here)

The compiled logger wrapper in the MS Teams extension swallows structured data — debug() and info() only pass the first argument to the underlying logger, silently dropping context objects. This made diagnosing the root cause significantly harder. Tracked separately.

Related

Fixes #41390
Supersedes #41453 (closed due to branch deletion during conflict resolution)

Copilot AI review requested due to automatic review settings March 10, 2026 06:21
@openclaw-barnacle openclaw-barnacle bot added channel: msteams Channel integration: msteams size: S labels Mar 10, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR fixes a key mismatch in the MS Teams allowlist resolution: at startup, the Graph API GUID was stored as the team key, but at runtime Bot Framework sends the General channel's conversation ID as channelData.team.id, causing inbound messages to silently fail policy lookup. The fix fetches the team's channel list upfront, finds the General channel, and uses its conversation ID as the stored team key — with a fallback to the Graph GUID if the General channel is absent.

Strengths:

  • The core fix is correct and well-motivated; the new test cases clearly document the expected behavior (General channel resolution for team-only entries, fallback to Graph GUID when General is missing).

Concern:

  • listChannelsForTeam is now called unconditionally for all team entries, including team-only entries that never required an external API call before. The current implementation lacks error handling: if the channels API call throws (network error, rate limit, permissions), the exception propagates uncaught and team-only entries that previously resolved cleanly will now fail entirely. The fallback (generalChannel?.id ?? graphTeamId) only covers the success path where the API returns no General channel. A try/catch wrapper would align with the stated fallback intent and prevent regression in degraded-network or rate-limited scenarios.

Confidence Score: 3/5

  • The fix correctly addresses the key mismatch but introduces uncaught error propagation for a previously-safe code path.
  • The core fix is sound and the happy-path tests are good. However, team-only entries now unconditionally call listChannelsForTeam (line 132) without try/catch protection. A transient API failure that was previously harmless will now cause team-only entries to fail entirely — this is a meaningful regression risk in degraded-network or rate-limited scenarios. The error-handling gap is straightforward to fix but should be addressed before merge.
  • extensions/msteams/src/resolve-allowlist.ts (error handling around line 132)

Last reviewed commit: 781f45b

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes MS Teams allowlist resolution to use the same team identifier that Bot Framework sends at runtime (channelData.team.id), preventing inbound channel messages from being dropped due to a key mismatch.

Changes:

  • Resolve a team’s config key to the General channel conversation ID (instead of the Graph group GUID).
  • Fetch team channels once during resolution and reuse them for channel matching.
  • Extend/adjust unit tests to cover team-only resolution and the “General missing” fallback.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
extensions/msteams/src/resolve-allowlist.ts Changes team key resolution to prefer the General channel conversation ID and reuses a single channel list lookup.
extensions/msteams/src/resolve-allowlist.test.ts Updates expectations and adds test cases for team-only entries and the fallback path.

@onutc onutc self-assigned this Mar 10, 2026
BradGroux and others added 4 commits March 10, 2026 09:05
… Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390
@onutc onutc force-pushed the fix/msteams-team-key-format branch from 89ef482 to 8a77dc5 Compare March 10, 2026 08:13
@onutc onutc merged commit 568b0a2 into openclaw:main Mar 10, 2026
@onutc
Copy link
Copy Markdown
Contributor

onutc commented Mar 10, 2026

Landed via temp rebase onto main.

  • Gate: pnpm lint && pnpm build && pnpm test
  • Land commit: 8a77dc5
  • Merge commit: 568b0a2

Thanks @BradGroux!

Get-windy pushed a commit to Get-windy/JieZi-ai-PS that referenced this pull request Mar 10, 2026
上游更新摘要(abb8f6310 → bda63c3,164 commits):

### 新功能
- ACP: 新增 resumeSessionId 支持 ACP session 恢复(openclaw#41847)
- CLI: 新增 openclaw backup create/verify 本地状态归档命令(openclaw#40163)
- Talk: 新增 talk.silenceTimeoutMs 配置项,可自定义静默超时(openclaw#39607)
- ACP Provenance: 新增 ACP 入站溯源元数据和回执注入(openclaw#40473)
- Brave 搜索: 新增 llm-context 模式,返回 AI 精炼摘要(openclaw#33383)
- browser.relayBindHost: Chrome relay 可绑定非 loopback 地址(WSL2 支持)(openclaw#39364)
- node-pending-work: 新增 node.pending.pull/ack RPC 接口
- Telegram: 新增 exec-approvals 处理器,支持 Telegram 内命令执行审批
- Mattermost: 新增 target-resolution,修复 markdown 保留和 DM media 上传
- MS Teams: 修复 Bot Framework General channel 对话 ID 兼容性(openclaw#41838)
- secrets/runtime-web-tools: 全新 web runtime secrets 工具模块
- cron: 新增 store-migration,isolated-agent 直送核心通道,delivery failure notify
- TUI: 自动检测浅色终端主题(COLORFGBG),支持 OPENCLAW_THEME 覆盖(openclaw#38636)

### 修复
- macOS: launchd 重启前重启已禁用服务,修复 openclaw update 卡死问题
- Telegram DM: 按 agent 去重入站 DM,防止同一条消息触发重复回复(openclaw#40519)
- Matrix DM: 修复 m.direct homeserver 检测,保留房间绑定优先级(openclaw#19736)
- 飞书: 清理插件发现缓存,修复 onboarding 安装后重复弹窗(openclaw#39642)
- config/runtime snapshots: 修复 config 写入后 secret 快照丢失问题(openclaw#37313)
- browser/CDP: 修复 ws:// CDP URL 反向代理和 wildcard 地址重写
- agents/failover: 识别 Bedrock tokens per day 限额为 rate limit

### 版本
- ACPX 0.1.16
- iOS/macOS 版本号更新
- Android: 精简后台权限

构建验证:待执行
mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Mar 10, 2026
* main: (43 commits)
  docs: add openclaw#42173 to CHANGELOG — strip leaked model control tokens (openclaw#42216)
  Agents: align onPayload callback and OAuth imports
  docs: add Tengji (George) Zhang to maintainer table (openclaw#42190)
  fix: strip leaked model control tokens from user-facing text (openclaw#42173)
  Changelog: add unreleased March 9 entries
  chore: add .dev-state to .gitignore (openclaw#41848)
  fix(agents): avoid duplicate same-provider cooldown probes in fallback runs (openclaw#41711)
  fix(mattermost): preserve markdown formatting and native tables (openclaw#18655)
  feat(acp): add resumeSessionId to sessions_spawn for ACP session resume (openclaw#41847)
  ACPX: bump bundled acpx to 0.1.16 (openclaw#41975)
  mattermost: fix DM media upload for unprefixed user IDs (openclaw#29925)
  fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility (openclaw#41838)
  fix(mattermost): read replyTo param in plugin handleAction send (openclaw#41176)
  fix(sandbox): pass real workspace to sessions_spawn when workspaceAccess is ro (openclaw#40757)
  fix(ui): replace Manual RPC text input with sorted method dropdown (openclaw#14967)
  CI: select Swift 6.2 toolchain for CodeQL (openclaw#41787)
  fix(agents): forward memory flush write path (openclaw#41761)
  fix(telegram): move network fallback to resolver-scoped dispatchers (openclaw#40740)
  fix(security): harden replaceMarkers() to catch space/underscore boundary marker variants (openclaw#35983)
  fix(web-search): recover OpenRouter Perplexity citations from message annotations (openclaw#40881)
  ...
Moshiii pushed a commit to Moshiii/openclaw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
Moshiii pushed a commit to Moshiii/openclaw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
frankekn pushed a commit to MoerAI/openclaw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
frankekn pushed a commit to Effet/openclaw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
frankekn pushed a commit to ImLukeF/openclaw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
dominicnunez pushed a commit to dominicnunez/openclaw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
ahelpercn pushed a commit to ahelpercn/openclaw that referenced this pull request Mar 12, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
Ruijie-Ysp pushed a commit to Ruijie-Ysp/clawdbot that referenced this pull request Mar 12, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
qipyle pushed a commit to qipyle/openclaw that referenced this pull request Mar 12, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
… Framework compatibility (openclaw#41838)

* fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility

Bot Framework sends `activity.channelData.team.id` as the General channel's
conversation ID (e.g. `19:[email protected]`), not the Graph API group GUID
(e.g. `fa101332-cf00-431b-b0ea-f701a85fde81`). The startup resolver was
storing the Graph GUID as the team config key, so runtime matching always
failed and every channel message was silently dropped.

Fix: always call `listChannelsForTeam` during resolution to find the General
channel, then use its conversation ID as the stored `teamId`. When a specific
channel is also configured, reuse the same channel list rather than issuing a
second API call. Falls back to the Graph GUID if the General channel cannot
be found (renamed/deleted edge case).

Fixes openclaw#41390

* fix(msteams): handle listChannelsForTeam failure gracefully

* fix(msteams): trim General channel ID and guard against empty string

* fix: document MS Teams allowlist team-key fix (openclaw#41838) (thanks @BradGroux)

---------

Co-authored-by: bradgroux <[email protected]>
Co-authored-by: Onur <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams size: S

Projects

None yet

3 participants