Skip to content

[Sentry: APP-KDF] HybridApp iOS fatal hang — RCTMarkdownUtils applyMarkdownFormatting blocks the main thread in the Yoga measure pass #99849

Description

@mountiny

Sentry

https://expensify.sentry.io/issues/APP-KDF

Impact (snapshot at filing)

  • Users (total since first seen): 37
  • Events: 42
  • Users (last 14d): 37
  • First seen: 2026-08-24 (Sentry substatus is still new)
  • Last seen: ongoing
  • Platform: iOS HybridApp
  • App version(s): 9.4.56-3, 9.4.57-3, 9.4.58-4, 9.4.59-5, 9.4.60-2
  • Mechanism: AppHang (Fatal App Hang Fully Blocked)
  • Culprit: -[RCTMarkdownUtils applyMarkdownFormatting:withDefaultTextAttributes:markdownStyle:parserId:]

Every affected user in the 14 day window is a new user of this signature, so this is a fresh
regression rather than a long tail.

Stack trace (top frames, main thread)

__ulock_wait2
_os_unfair_lock_lock_slow
objc_sync_enter
-[RCTMarkdownUtils applyMarkdownFormatting:withDefaultTextAttributes:markdownStyle:parserId:]
facebook::react::MarkdownTextInputDecoratorShadowNode::applyMarkdownFormattingToTextInputState
facebook::react::MarkdownTextInputDecoratorShadowNode::measureContent
facebook::react::MarkdownTextInputDecoratorShadowNode::yogaNodeMeasureCallbackConnector
facebook::yoga::Node::measure (Node.cpp:59)
facebook::yoga::measureNodeWithMeasureFunc (CalculateLayout.cpp:356)
facebook::yoga::calculateLayoutImpl (CalculateLayout.cpp:1349)
... ~100 further Yoga frames: calculateLayoutInternal / calculateLayoutImpl /
    computeFlexBasisForChild / resolveFlexibleLength / layoutAbsoluteDescendants ...
facebook::react::YogaLayoutableShadowNode::layoutTree (YogaLayoutableShadowNode.cpp:683)

The event also shows LiveMarkdownRuntime_queue and LiveMarkdownRuntime(timeout) threads alive
while the main thread sits in the lock.

Suspected cause

The Yoga measure callback for MarkdownTextInputDecoratorShadowNode calls
applyMarkdownFormatting synchronously on the main thread, and that method blocks on the
@synchronized lock inside RCTMarkdownUtils. The stack shows a very deep layout pass, roughly 100
Yoga frames with repeated layoutAbsoluteDescendants recursion, so the measure function is invoked
many times in one pass while the parser lock is held elsewhere. The main thread waits past the two
second watchdog threshold and iOS terminates the app.

Two things worth checking:

  1. Whether applyMarkdownFormatting can be made lock free on the measure path, or given a cached
    measurement so repeated measures of unchanged text do not re-enter the parser.
  2. Why the layout tree is this deep. The repeated absolute-position recursion suggests a markdown
    input nested inside several absolutely positioned containers, which multiplies measure calls.

Reproduction

Unknown — see the events linked from the Sentry issue. The affected sample includes iPad on iOS 26.6,
so a large composer with long markdown content is a plausible starting point.

Related

Issue OwnerCurrent Issue Owner: @Krishna2323

Activity

  1. self-assigned this
    on Aug 30, 2026
  2. melvin-bot commented on Sep 2, 2026

    @melvin-bot

    @mountiny Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  3. melvin-bot commented on Sep 3, 2026

    @melvin-bot

    @mountiny Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  4. melvin-bot commented on Sep 3, 2026

    @melvin-bot

    @mountiny Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  5. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Sep 3, 2026
  6. melvin-bot commented on Sep 3, 2026

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @Krishna2323 (External)

  7. melvin-bot commented on Sep 3, 2026

    @melvin-bot

    Unable to auto-create job on Upwork. The BZ team member should create it manually for this issue.

  8. melvin-bot commented on Sep 8, 2026

    @melvin-bot

    @Krishna2323 Eep! 4 days overdue now. Issues have feelings too...

  9. mountiny commented on Sep 10, 2026

    @mountiny
    ContributorAuthor

    @MelvinBot can you check this event in Sentry? Is it still reproducible in the latest versions?

  10. MelvinBot commented on Sep 10, 2026

    @MelvinBot
    Contributor

    Short answer: this should already be fixed as of App 9.4.65 — but I could not read Sentry to confirm no new events have landed since. My Sentry connection failed on this run, so everything below is from the code and version history, not from live event data.

    What I found

    Every affected version in the report (9.4.56-3 → 9.4.60-2) pinned @expensify/react-native-live-markdown at 0.1.334, which does not contain the fix for this exact hang.

    The fix is Fix main thread hang on iOS (#772), merged 2026-08-24. It targets precisely the stack in this issue — main thread stuck in objc_sync_enter inside applyMarkdownFormatting:…markdownStyle:parserId: during the Yoga measure pass. Both the lock inversion and the "measure parses synchronously" problem described in the issue body are addressed:

    • The @synchronized block now covers only the _markdownStyle/_parserId writes, so no lock is held across the worklet runtime call (apple/RCTMarkdownUtils.mm:48-51).
    • On a main-thread cache miss it warms the cache asynchronously and returns instead of entering the runtime (apple/RCTMarkdownUtils.mm:56-75).
    • A 4-entry parse cache replaced the single-entry memo, so repeated measures of unchanged text no longer re-enter the parser (apple/MarkdownParser.mm).

    Version chain

    live-markdown Has fix?
    App 9.4.56-3 … 9.4.64-3 0.1.334 ❌
    App 9.4.65-0 onward 0.1.336 ✅
    App main today (9.4.75-1) 0.1.336 ✅

    The bump landed in #99324 (merged 2026-08-29), first shipping in 9.4.65-0.

    Note the App-side patch PR referenced from #772 (#97871) was closed unmerged — the fix went upstream into the library instead and reached App via the version bump, so the coverage is real.

    What still needs a human

    1. Filter the Sentry issue to release >= 9.4.65. If APP-KDF has zero events on 9.4.65+, close it. If events are still arriving on those releases, the fix is incomplete and this needs reopening as a follow-up on Update version to 1.0.1-174 #772.
    2. I did not run a live repro. This is an iOS native watchdog hang; the tester available to me on this run drives web, which cannot reproduce or rule out an Objective-C lock stall on the iOS main thread.

    The linked prior-art issue #93831 (APP-EF1) is the same root cause — #772 names it directly — so both should clear together.


    Next Steps: Reply with @MelvinBot <your feedback> to refine this analysis.


    view run · view recording

  11. melvin-bot commented on Sep 10, 2026

    @melvin-bot

    @Krishna2323 Still overdue 6 days?! Let's take care of this!

  12. Krishna2323 commented on Sep 11, 2026

    @Krishna2323
    Contributor

    I'll review this today.

  13. melvin-bot commented on Sep 14, 2026

    @melvin-bot

    @Krishna2323 Whoops! This issue is 2 days overdue. Let's get this updated quick!

  14. melvin-bot commented on Sep 16, 2026

    @melvin-bot

    @Krishna2323 Eep! 4 days overdue now. Issues have feelings too...

  15. Krishna2323 commented on Sep 18, 2026

    @Krishna2323
    Contributor

    @mountiny Not reproducible on current builds, this is already fixed. All 59 events are on 9.4.64-3 or older, with zero events on 9.4.65+ despite those releases being in the wild (9.4.65-3 has 49 other iOS AppHangs in the last 7d).

    Fixed by 982c10c, bumping @expensify/react-native-live-markdown 0.1.334 → 0.1.336, which narrowed the @synchronized (self) block in RCTMarkdownUtils.applyMarkdownFormatting to just the two field assignments and stopped the Yoga measure path from parsing on the main thread. This was the fix for #93831 (APP-EF1), which turns out to be the same root cause as this one, rather than just prior art.

  16. mountiny commented on Sep 18, 2026

    @mountiny
    ContributorAuthor

    Thanks for looking into this, we can close this one then

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

Metadata

Metadata

Labels

DailyKSv2ExternalAdded to denote the issue can be worked on by a contributor

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions