facebook / metro

🚇 The JavaScript bundler for React Native
https://metrobundler.dev
MIT License
5.17k stars 614 forks source link

metro-symbolicate return always null:null:null from line/column search #1021

Open Aure77 opened 1 year ago

Aure77 commented 1 year ago

Do you want to request a feature or report a bug? bug

What is the current behavior? metro-symbolicate return always null:null:null from line/column search

I got stacktrace ike this:

Non-fatal Exception: io.invertase.firebase.crashlytics.a: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
       at .<unknown>(ErrorBoundary)
       at .renderWithHooks(address at index.android.bundle:1:237392)
...

I try:

➤ npx metro-symbolicate@0.72.3 index.android.bundle.packager.map 1 237392
null:null:null

or

➤ npx metro-symbolicate@0.72.3 index.android.bundle.packager.map 1
null:null:null

But it always return null:null:null

Did I miss something ? Il also tried npx metro-symbolicate@0.72.3 index.android.bundle.packager.map < stacktrace.txt but I got: TypeError: Line must be greater than or equal to 1, got 0

What is the expected behavior? should return function associated to line or column...

Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system. metro 0.72.3 react-native@0.70.8 node@16

SemihGk commented 1 year ago

I also have this issue.

metro@0.69.1 react-native@0.69.6 node@18

Did you find any workaround?

andrei-lt commented 12 months ago

+1, also hitting this problem. Crashes seem to symbolicate ok when using index.android.bundle.map instead of the .packager.map, but not always.

react-native@0.71.8 metro@0.73.10

SemihGk commented 11 months ago

I can also confirm that index.android.bundle.map seems to work fine, but not packager.map

dantenol commented 11 months ago

From some other issues and @SemihGk's comments I created a simple bash script to read the stacktrace file. All attempts using pure npx command with pipe inputs failed for me.

#!/bin/bash

# Define paths
sourcemapPath="android/app/build/generated/sourcemaps/react/release/index.android.bundle.map"
stackTracePath="stackTrace.txt"

# Throw if no stackTrace file
if [ ! -f "$stackTracePath" ]; then
  echo "No stackTrace file found"
  exit 1
fi

while IFS= read -r line; do
  if [[ $line == *'index.android.bundle'* ]]; then
    l=$(echo "$line" | sed -n 's/.*android\.bundle:\([0-9]*\):\([0-9]*\).*/\1/p')
    r=$(echo "$line" | sed -n 's/.*android\.bundle:\([0-9]*\):\([0-9]*\).*/\2/p')

    npx metro-symbolicate "$sourcemapPath" "$l" "$r"
  fi
done <"$stackTracePath"

Place it on your root folder along with the stacktrace file, then chmod +x the file and voilá.

How it works

The script first looks for the stacktrace and then iterates over each line that relates to a bundle location (code on the hermes bundle). For each line, it runs the npx metro-symbolicate command with its given line and column, so there are no issues regarding the format of the input file.

I know this is not optimized at all but is the only way that works efficiently for me.

Using metro-symbolicate@0.76.7 with RN@0.72.4

irisjae commented 9 months ago

A related problem I find is that using Hermes, the bundle.js file cannot even be found within the intermediates directory of the build (metro@0.76.8, metro-symbolicate@0.76.8, react-native@0.72.6). In place of the bundled Javascript, index.android.bundle gives only the Hermes bytecode, which I cannot comprehend.

In my scenario, I am attempting to debug a stack trace from adb logcat. As long as I can see relevant parts of the source code, I do not even mind whether it is mapped to source locations, or are bundled together (after all, the bundle.js is the most reliable source of the code actually being executed, with the results after any Babel plugin transformations). Without even the bundled file, this is fairly difficult.

I discovered that in the react-native gradle plugin, when building with Hermes, the code decides it wise to simply overwrite the Javascript bundle file with the Hermes bytecode. Here is a relevant patch that copies the bundle before it is overwritten, giving me a chance to at least inspect it. This is the file that works with index.android.bundle.packager.map. Note that this patch will leave the Javascript bundle file in the output apk as well, so its best to enable just it for debugging.

--- a/@react-native/gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt
+++ b/@react-native/gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt
@@ -84,6 +84,7 @@ abstract class BundleHermesCTask : DefaultTask() {
     val bundleAssetFilename = bundleAssetName.get()

     val bundleFile = File(jsBundleDir.get().asFile, bundleAssetFilename)
+    val bundleJsFile = File(jsBundleDir.get().asFile, bundleAssetFilename + ".js")
     val packagerSourceMap = resolvePackagerSourceMapFile(bundleAssetFilename)

     val bundleCommand = getBundleCommand(bundleFile, packagerSourceMap)
@@ -97,6 +98,7 @@ abstract class BundleHermesCTask : DefaultTask() {

       val hermesCommand = getHermescCommand(detectedHermesCommand, bytecodeFile, bundleFile)
       runCommand(hermesCommand)
+      bundleFile.copyTo(bundleJsFile)
       bytecodeFile.moveTo(bundleFile)

       if (hermesFlags.get().contains("-output-source-map")) {