Skip to content

fix(driver-utils): backport hasCompressionMarkup recursion fix for 2.82.1 (#27624)#27630

Open
arafat-java wants to merge 1 commit into
microsoft:release/client/2.82from
arafat-java:fix/backport-hascompressionmarkup-2.82.1
Open

fix(driver-utils): backport hasCompressionMarkup recursion fix for 2.82.1 (#27624)#27630
arafat-java wants to merge 1 commit into
microsoft:release/client/2.82from
arafat-java:fix/backport-hascompressionmarkup-2.82.1

Conversation

@arafat-java

Copy link
Copy Markdown
Contributor

Summary

Backports the fix from #27624 to release/client/2.82 for the upcoming 2.82.1 patch release.

hasCompressionMarkup() in DocumentStorageServiceCompressionAdapter used snapshot[key] instead of snapshot.trees[key] when recursing into ISnapshotTree subtrees. ISnapshotTree subtrees live under .trees, not as direct properties, so snapshot[key] was always undefined and the recursion silently never ran past the root level.

This became user-visible starting with Fluid 2.82 + SharedTree, where versionedSummarizer.ts can write a nested .metadata blob inside a DDS subtree. When putCompressionMarkup places .metadata.blobHeaders there, hasCompressionMarkup() fails to find it, _isCompressionEnabled stays false, and readBlob() returns raw LZ4-compressed bytes that fail JSON.parse with "Failed to get Channel: … is not valid JSON".

One functional line changed; no behavior change for backends where .metadata.blobHeaders is at the summary root (existing test fixtures, Azure FRS).

See #27624 for full repro details and verification against Autodesk's routerlicious backend.

Test plan

… → snapshot.trees[key] (microsoft#27624)

## The bug

`hasCompressionMarkup()` in `DocumentStorageServiceCompressionAdapter`
tries to recursively search the snapshot tree for the
`.metadata.blobHeaders` compression markup blob. The recursion was
silently broken:

```ts
for (const key of Object.keys(snapshot.trees)) {
-    const value = snapshot[key] as ISnapshotTree;   // always undefined
+    const value = snapshot.trees[key];              // correct
```

`ISnapshotTree` stores subtrees in `snapshot.trees`, not as direct
properties on the snapshot object. `snapshot[key]` is **always
`undefined`**, so the loop body never executes and
`hasCompressionMarkup()` only ever checks root-level blobs.

This meant `_isCompressionEnabled` stayed `false` when the
`.metadata.blobHeaders` markup blob was nested inside a DDS subtree,
causing `readBlob()` to return raw LZ4-compressed bytes that then hit
`JSON.parse` → **"Failed to get Channel: … is not valid JSON"**.

## Why it was latent until Fluid 2.82

Before Fluid 2.82, the `.metadata` blob (which determines where
`putCompressionMarkup` places the markup) was at the summary root.
`hasCompressionMarkup()` found it at root level without any recursion —
the bug didn't matter.

With Fluid 2.82 + SharedTree, `versionedSummarizer.ts` writes its own
`.metadata` blob inside the DDS subtree (`sheetSetData/`).
`findMetadataHolderSummary` finds this nested `.metadata` first (DFS),
so `putCompressionMarkup` places `.metadata.blobHeaders` inside
`sheetSetData/` — now the broken recursion matters and
`_isCompressionEnabled` is never set.

The bug has been present since microsoft#15656 and is in every release through
`client_v2.102.0` and current HEAD.

## The fix

One functional line changed. No behaviour change for backends where
`.metadata.blobHeaders` is at the root level (existing test fixtures and
Azure FRS).

## Verification

Tested against Autodesk's cedit/routerlicious backend (developer-dev
ring, `fluid` tenant) with a 2-client SharedTree + AWSClient repro
across `routerlicious-client` v4.0.3–v4.0.7 (Fluid 2.72–2.82):

- **Without fix:** v4.0.4–v4.0.7 reproduce "Failed to get Channel"
(`compress=1/2, decompress=0`)
- **With this fix only:** all 5 versions pass (`compress=1/2,
decompress≥1`)

Also confirmed: PropertyDDS never triggers the bug (its summarizer
writes no `.metadata` blob in the DDS subtree, so
`.metadata.blobHeaders` always lands at root).

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
(cherry picked from commit d639a8b)
@arafat-java arafat-java requested a review from a team July 1, 2026 01:44
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Warning

WARNING: This PR is targeting a release branch!

All changes must first be merged into main and then backported to the target release branch.
Please include a link to the main PR in the description of this PR.

Changes to release branches require approval from the Patch Triage group before merging.
You should have already discussed this change with them so they know to expect it.

For more details, see our internal documentation for the patch policy and processes for
patch releases.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Hi! Thank you for opening this PR. Want me to review it?

Based on the diff (5 lines, 1 files), I've queued these reviewers:

  • Correctness — logic errors, race conditions, lifecycle issues
  • Security — vulnerabilities, secret exposure, injection
  • API Compatibility — breaking changes, release tags, type design
  • Performance — algorithmic regressions, memory leaks
  • Testing — coverage gaps, hollow tests

How this works

  • Adjust the reviewer set by ticking/unticking boxes above. Reviewer toggles alone don't trigger anything.

  • Tick Start review below to dispatch the review fleet.

  • After review finishes, tick Start review again to request another run — it auto-resets after each dispatch.

  • This comment updates as new commits land; your reviewer selections are preserved.

  • Start review

@arafat-java

Copy link
Copy Markdown
Contributor Author

Warning

WARNING: This PR is targeting a release branch!

All changes must first be merged into main and then backported to the target release branch. Please include a link to the main PR in the description of this PR.

Changes to release branches require approval from the Patch Triage group before merging. You should have already discussed this change with them so they know to expect it.

For more details, see our internal documentation for the patch policy and processes for patch releases.

#27624

@arafat-java

Copy link
Copy Markdown
Contributor Author

@agarwal-navin
PR for backporting the fix (#27624) you merged to main

@CraigMacomber

Copy link
Copy Markdown
Contributor

This is targeting a no longer supported release. 2.110.0 is the current supported release branch for fluid framework client, which could be patched theoretically, but just waiting for today's 2.111.0 will be faster.

Additionally, we only do patches for regressions. I don't think this change was a regression, but just a general fix which should wait to come out in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants