agentleFS
LedgerHQLedgerHQ/ledger-live/.agents/skills/debug-rn-native-crash/SKILL.md

debug-rn-native-crash

Skill627 starsChanged 8 days agoMITView on GitHub

Investigate native React Native crashes (Fabric/Hermes/iOS) in ledger-live-mobile when JS error logs are missing or unhelpful. Use when the app dies silently, throws an NSException on iOS, or shows only a native stack trace.

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Only a native stack trace (RCTViewComponentView, RCTPerformMountInstructions, …) with no JS source

    line 12
  2. Distinctive:

    If the JS console already gives a clear stack, don't use this skill — read the JS error.

    line 16
  3. Distinctive:

    Stop the running app first (otherwise Xcode can't attach cleanly).

    line 36
  4. Very specific:

    If the watcher is broken, restart Metro with --reset-cache.

    line 80
  5. Distinctive:

    Don't guess at causes from the JS code alone — the native debugger is the source of truth.

    line 84
  6. Distinctive:

    Don't trust "the bug only happens when flag X is on" until the user has tested both states.

    line 85
  7. Distinctive:

    Don't apply five fixes at once.

    line 86

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Debug RN native crash

Trigger

The mobile app crashes with one of:

  • A native iOS exception (NSInternalInconsistencyException, RCTFatal, Fabric assertion)
  • Only a native stack trace (RCTViewComponentView, RCTPerformMountInstructions, …) with no JS source
  • "Failed to symbolicate" in Metro and no actionable JS error
  • Reproducible crash but unclear which RN component is at fault

If the JS console already gives a clear stack, don't use this skill — read the JS error.

Workflow

1. Capture the native exception from the simulator

xcrun simctl list devices booted   # get the booted sim UDID
xcrun simctl spawn <UDID> log show --last 5m --style compact \
  --predicate 'processImagePath CONTAINS "ledgerlivemobile" AND (eventMessage CONTAINS "Assertion failure" OR eventMessage CONTAINS "Attempt to unmount" OR eventMessage CONTAINS "Terminating app")'

Extract the exception message, native stack, and any view descriptors (frame, tag, backgroundColor, alpha). These already tell you a lot — see reference.md "Anatomy of a Fabric assertion message".

2. Reproduce under Xcode debugger

open apps/ledger-live-mobile/ios/ledgerlivemobile.xcworkspace
  • Stop the running app first (otherwise Xcode can't attach cleanly).
  • In Xcode: Cmd+8 → + → Exception Breakpoint → Objective-C → All.
  • Cmd+R to build + run + attach.
  • Reproduce the crash. Xcode pauses at objc_exception_throw.

3. Identify the offending React component

In the lldb console at the bottom of Xcode:

  1. Pick the frame that has the offending C++/ObjC code:
    bt              # full backtrace, find the frame in RN code
    frame select N  # N = the RN frame (often RCTPerformMountInstructions)
  2. Inspect the views referenced by the failed instruction. Variable names depend on the frame — read the source displayed in Xcode. Common ones:
    po parentViewDescriptor.view
    po oldChildViewDescriptor.view
    p  mutation.parentTag
    p  mutation.index
    p  oldChildShadowView.componentName
  3. Find where the orphan child is actually attached vs where Fabric thinks:
    po [oldChildViewDescriptor.view superview]
    po [oldChildViewDescriptor.view accessibilityIdentifier]   # = RN testID
    po [parentViewDescriptor.view superview]
    po [[parentViewDescriptor.view superview] accessibilityIdentifier]
    po [parentViewDescriptor.view subviews]
  4. Climb the superview chain until you hit a accessibilityIdentifier (= RN testID) you recognise in source. Grep for it:
    grep -rn 'testID="<identifier>"' apps/ledger-live-mobile/src libs/ui
    That's the RN component family. From there, read the JSX and find the conditional render / animation / library that produced the mismatch.

4. Map the native cause to a code pattern

The vast majority of Fabric assertions come from a small set of patterns. See reference.md "Common Fabric crash patterns".

5. Fix and verify Metro actually serves the fix

A common trap: Metro's file watcher dies on EMFILE: too many open files. Edits silently never reach the bundle. Always confirm Metro logged a fresh Compiled ios in Xs line after each edit (in the terminal running pnpm mobile start:ios, or wherever Metro's stdout is streaming).

If the watcher is broken, restart Metro with --reset-cache. Reload the app (Cmd+R in sim or shake → Reload).

Guardrails

  • Don't guess at causes from the JS code alone — the native debugger is the source of truth.
  • Don't trust "the bug only happens when flag X is on" until the user has tested both states. Correlation in mobile apps is often coincidental (cold start vs hot reload, cache state, etc.).
  • Don't apply five fixes at once. Apply one, verify Metro served it, retest. Each silent failed iteration is wasted hours.

Output

  • The exact React component identified as the orphan (from accessibilityIdentifier / testID)
  • The pattern name (e.g. "Reanimated withRepeat on unmount", "unstable keyExtractor")
  • The minimal fix applied
  • Confirmation Metro served the fix and the crash no longer reproduces

Reference

See reference.md in this folder for:

  • Anatomy of a Fabric assertion message
  • lldb cheatsheet for Fabric mount errors
  • Catalogue of common Fabric crash patterns with code-side fixes

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.