Port channelData optional-subfield fix (#564) to 2.1 (2.1.0-alpha.2) - #567
Merged
Conversation
Fixes #563 The Teams service can send nested `channelData` objects as empty objects ( `{}` ). Because `AppInfo.id` was required, Pydantic raised a `ValidationError`, and since `ActivityTypeAdapter.validate_python` has no fallback, the entire activity was rejected, so affected bots silently stopped responding. Reported against 2.0.15, the first release containing #504. Confirmed to affect customers, currently in 1:1 chats, with exposure growing as an upstream server-side rollout ramps. ## Root cause `channelData.app` is optional, so an absent `app` was always fine, but a present but empty one wasn't. Auditing the model graph showed this isn't unique to `app`: 98 sites exist where an optional parent points at a child with required fields. Seven were reachable from a plain message activity: ``` channelData.app={} -> channelData.app.id Field required channelData.channel={} -> channelData.channel.id Field required channelData.team={} -> channelData.team.id Field required channelData.tenant={} -> channelData.tenant.id Field required channelData.settings={} -> channelData.settings.selectedChannel attachments=[{}] -> attachments.0.contentType entities=[{}] -> entities.0._unknown.type ``` ## Change Make these inbound-only fields optional: `AppInfo.id`, `ChannelInfo.id`, `TeamInfo.id`, `TenantInfo.id`, `ChannelDataSettings.selected_channel`, `Attachment.content_type`, `EntityBase.type`. `MessageUpdateChannelData` and `MessageDeleteChannelData` both inherit `ChannelData`, so they're covered without separate edits. `EntityBase.type` is relaxed at the base rather than overridden on `UnknownEntity`: every concrete entity already overrides `type` with a `Literal` default, so `UnknownEntity` is the only class inheriting it raw. This also means an entity type introduced after this SDK version no longer drops the message. ## Tests New `test_empty_inbound_objects.py` covering each empty-object case, an unrecognized entity type, that populated values still parse, and that absent `channelData` is unchanged. ## Validation - 852 tests pass across `packages/api` + `packages/apps` - `ruff format` / `ruff check` clean - pyright: zero net new errors ## Notes This is the defensive half. The empty object is a service-side wire-contract issue and has been raised with that team separately; this change means the SDK degrades gracefully regardless. (cherry picked from commit 5fcd8fa)
Target 2.1.0-alpha.2. The backport adds 2 commits plus the merge commit, putting the merge commit at height 16, so the offset moves -12 -> -14. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mehak Bindra (MehakBindra)
approved these changes
Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backports #564 onto the 2.1 preview train and lines the version up for
2.1.0-alpha.2.What
#564 ("Make channelData subfields optional to avoid throw", fixes #563): the Teams service can send nested
channelDataobjects as empty ({}), which made Pydantic reject the whole activity, so affected bots silently stopped responding. Regression from #504.Commits
Make channelData subfields optional to avoid throw (#564)— cleangit cherry-pick -xof5fcd8fafrommain, zero conflictsPreserve alpha sequence after backport merge—versionHeightOffset-12->-14Why the offset moves
release/v2.1HEAD currently evaluates to2.1.0-alpha.1, which is already published to PyPI (2.1.0a1, 2026-08-03), so this release has to land onalpha.2.nbgv height resets only when the
versionstring changes, andversionHeightOffsetedits do not reset it. Following the same shape as #544:release/v2.1(f469008)So
offset = 2 - 16 = -14.Verified by simulating the merge locally on a branch named
release/v2.1(so it matchespublicReleaseRefSpec):Merge instructions
Important
Merge with a merge commit, not squash. The offset above assumes the merge commit exists. A squash merge would put the tip at height 15 and republish
alpha.1.Re-run
nbgv get-version -v SemVer2onrelease/v2.1after merging and confirm it prints2.1.0-alpha.2before triggering the pipeline. If it is off, note that a corrective offset commit itself adds height, so recompute and re-verify.Validation
pytest packages— 952 passedpyright— 0 errors, 0 warningsruff check— All checks passedruff format --check— 459 files already formattedPublishing
ADO publish pipeline on
release/v2.1, Publish Type = Public. The pipeline detects the-in the version and uses PyPI dist-tagnext, so it will not displacelatest. Lands on PyPI as2.1.0a2.Depends on / pairs with #566 (2.0.16 on the pre-2.1 train).