Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NODE_BINARY in .xcode.env not working #35657

Closed
MicahDavid opened this issue Dec 15, 2022 · 36 comments
Closed

NODE_BINARY in .xcode.env not working #35657

MicahDavid opened this issue Dec 15, 2022 · 36 comments

Comments

@MicahDavid
Copy link

Description

I would like to use the .xcode.env to set my node version. My .xcode.env looks like:

export NODE_BINARY=$(command -v node)

When I execute this command in a terminal window, it returns the proper node version. I've tested, and the only way I can set the node version is using Build Phases -> Bunde React Native Code and Images -> and exporting NODE_BINARY in the shell commands there to the absolute path:

export NODE_BINARY=/Users/myuser/.nvm/versions/node/v14.18.1/bin/node

Can anyone suggest why NODE_BINARY is not being set through the .xcode.env file? Do I have to take any extra steps to use this during archive?

Version

0.70.4

Output of npx react-native info

System:
OS: macOS 12.6
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 23.84 MB / 32.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 14.18.1 - ~/.nvm/versions/node/v14.18.1/bin/node
Yarn: 1.22.18 - ~/.nvm/versions/node/v14.18.1/bin/yarn
npm: 6.14.15 - ~/.nvm/versions/node/v14.18.1/bin/npm
Watchman: 2022.03.21.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.3 - /Users/micahsklut/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1
Android SDK:
API Levels: 29, 30, 31
Build Tools: 29.0.2, 30.0.2, 30.0.3, 31.0.0
System Images: android-29 | Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom_64, android-30 | Google APIs Intel x86 Atom
Android NDK: Not Found
IDEs:
Android Studio: 2021.3 AI-213.7172.25.2113.9123335
Xcode: 14.2/14C18 - /usr/bin/xcodebuild
Languages:
Java: 1.8.0_292 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 18.1.0 => 18.1.0
react-native: ^0.70.4 => 0.70.6
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Steps to reproduce

Run Archive. The system node is being used, unless I set it as explained above.

Snack, code example, screenshot, or link to a repository

Screen Shot 2022-12-15 at 6 29 09 PM

@codesalley
Copy link

in my case it was NVM. Either let nvm go or reconfigure it In your build phases scripts

if [[ -s "$HOME/.nvm/nvm.sh" ]]; then
. "$HOME/.nvm/nvm.sh"
elif [[ -x "$(command -v brew)" && -s "$(brew --prefix nvm)/nvm.sh" ]]; then
. "$(brew --prefix nvm)/nvm.sh"
fi

@jaimeagudo
Copy link

In my case I had to add export NODE_BINARY=$(command -v node)\n to the PODS build phases script tail, .xcode.env seemed to make no difference

shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\nexport NODE_BINARY=$(command -v node)\n";

Running react-native": "0.69.7" on arm64

@jaimeagudo
Copy link

Apparently this is caused by nvm A less invasive workaround (that breaks nvm):

ln -s $(which node) /usr/local/bin/node

@djMax
Copy link

djMax commented Apr 27, 2023

nvm is common enough that I would suggest this should work out of the box.

@badsyntax
Copy link

Loading nvm from within .xcode.env seems to resolve this for me:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

export NODE_BINARY=$(command -v node)

@lucianomlima
Copy link
Contributor

In my Xcode build logs show me this error:

../node_modules/react-native/scripts/xcode/with-environment.sh: line 35: node: command not found

But after errors, show "Now using node v20.7.0." and this happen too with Upload Debug Symbols to Sentry build phase.
I'm using Xcode 14.3.1 and RN v0.69.12.
Everything works on terminal (iTerm + zsh)

@cipolleschi
Copy link
Contributor

The problem is that Xcode scripts works in a different environment than a regular terminal/
Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.

If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it.
A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

@lucianomlima
Copy link
Contributor

lucianomlima commented Oct 8, 2023

The problem is that Xcode scripts works in a different environment than a regular terminal/
Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.

If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it.
A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

In my case, Xcode can find node (using the ,export NVM_DIR=path/to/.nvm approach) but can't find command, that is a built-in shell library.
Sounds weird.

@cipolleschi
Copy link
Contributor

@lucianomlima yeah, that's definitely very weird.
Can you try add a script phase after building just calling which command? :/

@lucianomlima
Copy link
Contributor

which command shows me : command: shell built-in command but I do some tests and I realize that nothing going work with Xcode build and .xcode.env.
Now my .xcode.env is:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" --no-use

nvm use default # I need to put this because when use nvm current returns none

export NODE_BINARY=$NVM_DIR/versions/node/v20.7.0/bin/node

echo $NVM_DIR # Prints /Users/luciano.lima/.nvm
echo $NODE_BINARY # Prints /Users/luciano.lima/.nvm/versions/node/v20.7.0/bin/node

And, on Xcode log, I have these messages:

Now using node v20.7.0 (npm v10.1.0)
/Users/luciano.lima/.nvm # echo $NVM_DIR
/Users/luciano.lima/.nvm/versions/node/v20.7.0/bin/node # echo $NODE_BINARY
Node found at: /Users/luciano.lima/.nvm/versions/node/v20.7.0/bin/node

And some time later:

+ type node
+ echo 'error: node not found! Modules won'\''t be collected.' 'Please export NODE_BINARY in '\''Build Phase'\'' - '\''Bundle React Native code and images'\''' 'to an absolute path of your node binary. Check your node path by '\''which node'\''.'
error: node not found! Modules won't be collected. Please export NODE_BINARY in 'Build Phase' - 'Bundle React Native code and images' to an absolute path of your node binary. Check your node path by 'which node'.
+ exit 0
Command PhaseScriptExecution emitted errors but did not return a nonzero exit code to indicate failure

So, even using an absolute path to NODE_BINARY, build script phase fails.

The only way that make things works is with symlink like @cipolleschi suggests. Now my .xcode.env have only this:

export NODE_BINARY=/usr/local/bin/node

And now finally works. 🤷

@cipolleschi
Copy link
Contributor

From which script phase the message:

+ type node
+ echo 'error: node not found! Modules won'\''t be collected.' 'Please export NODE_BINARY in '\''Build Phase'\'' - '\''Bundle React Native code and images'\''' 'to an absolute path of your node binary. Check your node path by '\''which node'\''.'
error: node not found! Modules won't be collected. Please export NODE_BINARY in 'Build Phase' - 'Bundle React Native code and images' to an absolute path of your node binary. Check your node path by 'which node'.
+ exit 0
Command PhaseScriptExecution emitted errors but did not return a nonzero exit code to indicate failure

arrives? I have no memory of any of our scripts emitting that message! Could it be a third party library?
The problem is likely that that script is not using loading the with-environment.sh script that is responsible to load the .xcode.env. Without loading that, it is expected not to find the ENV vars.

@lucianomlima
Copy link
Contributor

It's from @sentry/react-native and my script build phase is

export SENTRY_PROPERTIES=sentry.properties
export EXTRA_PACKAGER_ARGS="--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map"
set -e

WITH_ENVIRONMENT="../node_modules/react-native/scripts/xcode/with-environment.sh"
REACT_NATIVE_XCODE="../node_modules/react-native/scripts/react-native-xcode.sh"
SENTRY_CLI="../node_modules/@sentry/cli/bin/sentry-cli"

/bin/sh -c "$WITH_ENVIRONMENT \"$SENTRY_CLI react-native xcode $REACT_NATIVE_XCODE\""
/bin/sh ../node_modules/@sentry/react-native/scripts/collect-modules.sh

Maybe the last line is where the problem is? I'll try to add WITH_ENVIRONMENT to it.

@adamjw3
Copy link

adamjw3 commented Oct 14, 2023

i think i'm getting a similar issue

Node found at: /opt/homebrew/bin/node
/Users/adamwright/Documents/Development/AB3MobileUpgrade/AB3MobileUpgrade/ios/Pods/../../node_modules/react-native/React/FBReactNativeSpec/../../scripts/react_native_pods_utils/script_phases.sh: line 34: /opt/homebrew/bin/node: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code

My .xcode.env is

# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.
# For example, to use nvm with brew, add the following line
# . "$(brew --prefix nvm)/nvm.sh" --no-use
export NODE_BINARY=$(command -v node)export NODE_BINARY=/opt/homebrew/bin/node

but my node path when running which node is - /usr/local/bin/node

How can i fix this?

@cipolleschi
Copy link
Contributor

Hey @adamjw3! Your Xcode env has 2 export NODE_BINARY on the same line.
That would not work.

You should have either

export NODE_BINARY=$(command -v node)

Or

export NODE_BINARY=/usr/local/bin/node

@adamjw3
Copy link

adamjw3 commented Oct 15, 2023

@cipolleschi thanks, they are on two lines in the file and it was auto generated like that! i commented out

export NODE_BINARY=$(command -v node)

and updated the other with my node path

export NODE_BINARY=/usr/local/bin/node

project now builds

Thanks

@jswangtao
Copy link

I am using RN version 0.72.3, which can run, package and flash back. I feel that it is the reason for switching to the default version with NVM. I have added a script here, and switching to 20 or above is normal. It should be 18, but our team is using 20, so switching to 20 is necessary
image

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

nvm use 20

export NODE_BINARY=node
../node_modules/react-native/scripts/react-native-xcode.sh

@banane
Copy link

banane commented Nov 28, 2023

What worked for us was to get the NVM directory:
export NODE_BINARY=$HOME/.nvm/nodes/versions/v18.0.0/bin/node

We have NVM setup in our README so could reasonably expect local devs to have that set, and doesn't to explicitly state the node version. Then, it runs same locally and on CircleCi.

@aTreey
Copy link

aTreey commented Jan 29, 2024

The problem is that Xcode scripts works in a different environment than a regular terminal/ Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.

If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it. A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

This analysis is correct. I solved this problem by completely uninstalling node and then downloading the .pkg installation from the node.js ,because the installation location of the installation package is /usr/local/bin/node by default.

@gabriellend
Copy link

gabriellend commented Feb 12, 2024

Just adding more info in case it's helpful. I'm using Homebrew and this is happening too, right after downgrading from node 20 to node 18. Not using Expo, RN 0.70.6. Here are some of the xcode logs when the error occurs:

...Desktop/Inventory/ios/Pods/../../node_modules/react-native/React/FBReactNativeSpec/../../scripts/xcode/with-environment.sh: line 35: .xcode.env: command not found
.../Desktop/Inventory/ios/Pods/../../node_modules/react-native/React/FBReactNativeSpec/../../scripts/xcode/with-environment.sh: line 35: node: command not found
[Warning] You need to configure your node path in the environment. You can set it up quickly by running: echo 'export NODE_BINARY=' > .xcode.env in the ios folder. This is needed by React Native to work correctly. We fallback to the DEPRECATED behavior of finding . This will be REMOVED in a future version. You can read more about this here: https://reactnative.dev/docs/environment-setup#optional-configuring-your-environment
[Error] Could not find node. It looks like that the .xcode.env or .xcode.env.local
Command PhaseScriptExecution failed with a nonzero exit code

I have .xcode.env inside my ios folder with the line: export NODE_BINARY=$(command -v node). command -v node prints out the correct path(/opt/homebrew/opt/node@18/bin/node). Switching out $(command -v node) with that path works.

I get now that Xcode runs in a different environment that doesn't have access to variables that the terminal has, but it was working before I changed the node version, and that is all I changed, so it seems weird that it suddenly wouldn't work.

@guikubivan
Copy link

Note, this other issue seems to suggest the .xcode.env thing will fix it, so just referencing here that that solution does not work: #33695

@moulie415
Copy link

This fixed the issue for me https://stackoverflow.com/a/66497247/6590549. I had a symlinked version of node that was node longer actually installed via nvm.

@neuron-mobility-frontend

Apparently this is caused by nvm A less invasive workaround (that breaks nvm):

ln -s $(which node) /usr/local/bin/node

The problem is that Xcode scripts works in a different environment than a regular terminal/ Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.
If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it. A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

This analysis is correct. I solved this problem by completely uninstalling node and then downloading the .pkg installation from the node.js ,because the installation location of the installation package is /usr/local/bin/node by default.

Thanks for good answer. The important thing is uninstalling unused node version.

@vinnyA3
Copy link

vinnyA3 commented May 20, 2024

I created an .xcode.env.local file and modified my NODE_BINARY path there -- local will override the default that you may have configured for the project in .xcode.env (just make sure not to commit your .xcode.env.local)

For context: I'm lazy-loading nvm, so I just made sure to load it up and set the correct path in my local file.

@ArindamRayMukherjee
Copy link

ArindamRayMukherjee commented May 25, 2024

I just spent half a day debugging a strange problem. XCode seems to be exiting with error code 65 due to the autogenerated .xcode.env.local. On deleting that file the next xcode-build command works fine.
Here's the sequence of events.

  1. Everything working fine for my mobile app codebase for deployment to the local iOS simulator
  2. Upgraded to RN 0.74.1 (don't know if this is related though)
  3. Ran local deployment react-native run-ios to iOS simulator, everything works fine.
  4. In the next run of react-native run-ios, xcode-build exits with an error code 65 .
  5. I try cleaning the various generated dirs using these two yarn commands "cleanstall": "rm -fr node_modules ios/Podfile.lock ios/Pods ios/build ~/Library/Developer/Xcode/DerivedData && yarn install" and "run-ios": "cd ios && rm -f Podfile.lock && pod repo update && NO_FLIPPER=1 RCT_NEW_ARCH_ENABLED=1 pod install && cd .. && react-native run-ios --verbose", but problem persists.
  6. Opening project in XCode and debugging it there shows it exits just after accessing .xcode.env.local which has this line export NODE_BINARY=/var/folders/_r/51ztwzn17fd1qzm2l87zjzz40000gn/T/yarn--1716631514203-0.5113628975765909/node. I think strange because .xcode.env has export NODE_BINARY=$(command -v node) and that just works fine to point out the right node binary.
  7. I delete .xcode.env.local and do react-native run-ios again and things work fine again.
  8. I find this thread and try to reproduce the sequence of events so I could add screenshots etc here, but 3 does NOT fail anymore!

Apologies for the long description, just trying to paint as detailed a picture so something clicks for someone who knows the picture deeper. This behaviour is worrisome because its an obscure problem that might revisit in a couple of months and burn another half day.

Are there any preventive measures I can take? For example I was thinking of making .xcode.env.local the same as .xcode.env so it also has export NODE_BINARY=$(command -v node) and committing that to the repo (so far these files were being mentioned in .gitignore )

@vinnyA3
Copy link

vinnyA3 commented May 25, 2024

@ArindamRayMukherjee Don't worry about .xcode.env.local, it's meant to override the project's configured node version in .xcode.env. Depending on how one manages node versions, it might be needed to override (see my previous comment above).

Don't commit it. First, double check that it's not already committed in the repo -- it maybe ignored by git now, but perhaps someone committed it by mistake before. If it in the repo, my recommendation is to open a PR to remove it.

@ArindamRayMukherjee
Copy link

@vinnyA3
Apologies, I had not succeeded in putting the question through properly. I've updated my comment above, may I request a second read through?
I'm trying to understand why an autogenerated file .xcode.env.local causes XCode to exit with code 65.
Moreover this happens sporadically, not always.
One thing is for certain, after a Xcode error 65 happens, deleting .xcode.env.local causes the next build to work.
See the man extract below for what the error means(quite generic as you can see).
man_syscode_exit_exit_code_65 copy

Committing .xcode.env.local with same contents as .xcode.env so it also has export NODE_BINARY=$(command -v node) was meant to act as a possible preventive measure so other team mates do not face the same issue. It is quite hard to trace back from a code 65 exit that .xcode.env.local is the problem.

@vinnyA3
Copy link

vinnyA3 commented May 26, 2024

@ArindamRayMukherjee why the local file is causing that specific error, I'm not sure. There must be more info in the log view of xcode. I have had issues the bundle phase script failing, and the source was because of the default xcode env file -- maybe it's the same error? Not sure off top of my head.

That said, I did find out that, depending how the project is configured, pod install can auto-generate the file:
#43285

It's not clear to me why this file is autogenerated in the first place, but if you check that thread, there are solutions

@ArindamRayMukherjee
Copy link

@vinnyA3 Many thanks! Yes that thread exactly mentions this! And I've gone for the simple solution of removing the file in my yarn commands.

@WilGatlin
Copy link

On 0.71.17, we found the only way to solve this error was to temporarily delete .xcode.env. You are able to add it back after a successful build and the rebuild without issues.

@betopompolo
Copy link

betopompolo commented Jul 1, 2024

I got the following setup on my local:

  • macOS Sonoma 14.5
  • nvm (without brew installation)
  • .nvmrc file on my project's root folder
  • React Native 0.74.3
  • I have not run the sudo ln -s $(command -v node) /usr/local/bin/node command

I did almost the same modifications as @lucianomlima (here) to my .xcode.env. Here's the complete file:

# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.

# Usage with nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm use $(<../.nvmrc) # Considering that .xcode.env is at ios/ and .nvmrc is at project's root
export NODE_BINARY="$(command -v node)"

and it's working! 🎉

@jspizziri
Copy link

jspizziri commented Aug 21, 2024

The issue for me seems to be that bash scripts are executing differently when run via an xcode build vs triggering a build from the CLI.

Specifically, the issue seems to be that command -v node behaves differently in these contexts.

yarn ios succeeds consistently, however xcode builds failed. You can modify your (my) .xcode.env file to illustrate the issue:

export NODE_BINARY=$(command -v node)
echo ">>>>>>>>> node binary path: $NODE_BINARY"
echo ">>>>>>>>>> PATH $PATH"

If you look at the build logs in Xcode you'll see that $NODE_BINARY is an empty string, whereas when triggered from CLI it's correct. I decided to log out my PATH in both contexts to see what was up and that's clearly what the issue is. The path when scripts are executed with Xcode is dramatically different from the path in my terminal:

xcode's paths

/Applications/Xcode.app/Contents/...
...
/Applications/Xcode.app/Contents/Developer/usr/local/bin
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin

terminal paths

...
# this is the big one for me 👇
/opt/homebrew/bin
...
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
...

In my case, I have node installed via homebrew (on an ARM machine) which installs node to /opt/homebrew/bin. This is all a much more verbose identification of the issue which was already stated here

Basically, you either need to make sure node exists in one of the bin paths that xcode includes in its paths OR you need to add an .xcode.env.local file and hardcode the path to your node bin.

@Voxar
Copy link

Voxar commented Sep 18, 2024

When xcode evaluates your .xcode.env it is not doing so from your USER env where node is installed via brew an version managers, but from a "clean shell" that does not know about any of your custom paths. It only works if node is available from /usr/bin, /usr/local/bin etc.

You should set up your own NODE_BINARY by running this from your command line: echo "export NODE_BINARY=$(command -v node)" > ios/.xcode.env.local

I would argue that this default setup with "export NODE_BINARY=$(command -v node)" in .xcode.env is incorrect and should be changed to something that respects the users environment, perhaps as a step at yarn install.

@Evan-Fisher
Copy link

Evan-Fisher commented Sep 30, 2024

Not seeing this posted anywhere. For me harcoding the path could work for some build processes but not for others, like React Native Code & Images. My path was opt/homebrew/bin/node which came from installing node via brew which is recommend by react native.

What worked immediately for me after trying basically everything else was uninstall node via brew (it was installed via brew) brew uninstall node. Install node via nodejs.org.

Then each build process was able to find node via export NODE_BINARY=$(command -v node)

@cipolleschi
Copy link
Contributor

We landed a change in main that should fix this for good: aa35a21

Johennes added a commit to unomed-dev/react-native-matrix-sdk that referenced this issue Oct 9, 2024
@FrederickEngelhardt
Copy link

@cipolleschi That solution looks like it works only if you have no xcode.env file. What about regenerating from existing projects or nodejs version upgrades?

For scalability across versions of nodejs or projects that have wrong version linked it would be best to do and diff on the binary path and compare it with the current output. Make sure it's exact then either replace it or skip. Also we could confirm it matches the .node-version of the project.

--

Recently had this problem went from node20 on my local clone and ran a pod install to test. Then ran into the nodejs issue. I symlinked fnm node version 20. it kept failing due to the mismatch or nodejs binaries (no yarn) on 20 vs 18.

@cipolleschi
Copy link
Contributor

That solution looks like it works only if you have no xcode.env file. What about regenerating from existing projects or nodejs version upgrades?

@FrederickEngelhardt this can't be done. If users customize their .xcode.env file with other configurations, we would wipe that away. Clearly, not a great experience.

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

No branches or pull requests