割とハマったのでメモ
Windows11上のWSLのUbuntu24.04でshファイル内でnpm run start
を実行していて以下のようなエラーに遭遇。
git cloneコマンド
で持ってきたプログラムだったのですが、他の環境ではこのようなエラーは発生していませんでした。
エラーの内容としてWindows側のプログラムを起動しようとしているみたいです。ファイルがなかったので何も発生しませんでしたが。
エラー表示
$ ./start_service.sh > y-websocket@2.0.4 start > node ./bin/server.cjs '\\wsl.localhost\Ubuntu24.04-TEST\home\user2404\y-websocket' 上記の現在のディレクトリで CMD.EXE を開始しました。 UNC パスはサポートされません。Windows ディレクトリを既定で使用 します。 node:internal/modules/cjs/loader:1147 throw err; ^ Error: Cannot find module 'C:\Windows\bin\server.cjs' at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15) at Module._load (node:internal/modules/cjs/loader:985:27) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12) at node:internal/main/run_main_module:28:49 { code: 'MODULE_NOT_FOUND', requireStack: [] } Node.js v20.10.0
想定していなかった動作でしたが、実際に発生することが確認できました。確かに、Windows側からWSLにあるプログラムを実行するのは可能です。
【参考】
このときはWSL上のsha256sum
を実行していました。
uepon.hatenadiary.com
今度は逆の現象でWSL側からWindowsのバイナリを実行しようとしていた。(でも、存在していなかったので失敗している)
わかったこと
WSLのディストリビューション上にないバイナリで、Windowsにあるバイナリがある場合にはそちらを動作させる可能性があるということです。
今回は、npm
がその原因になっていました。whichコマンド
(ファイルのパス確認)で見たところWSL
上のパスではなく、Windows上にあったことで明確になりました。
いつもは必要なコマンドを実行して(バージョン表示など)、アプリの有り無しを判定していたのですが、このような現象が起き得るとなるとかなり厳しいですね。whichコマンド
を使用したほうがいいような気がしてきました。
特に怖いのはnpm
やシェルスクリプト(*.sh)などで実行プログラムがいくつもあるときかもしれません。
どうすれば回避できるか?
以下のようにするのが対処療法としてはいいかなと思います。
# 現在の環境変数PATHを確認する方法 echo $PATH # Windowsのパスが含まれているか調べる方法 which node which npm # シェルスクリプト内でパスを明示的に指定する方法 #!/usr/bin/env bash export SHELL=/bin/bash export PATH=/usr/local/bin:/usr/bin:$PATH
こんな感じでしょうか。ちょっと面倒ですね😥。
恒久的な対策
これなら、Windows側のプログラムが動か異様にしてしまえばというのが次の手です。
以下の設定では、以下のようなことを行います。
1. /etc/wsl.confの修正・追記
# rootで/etc/wsl.confを編集
$ sudo nano /etc/wsl.conf
/etc/wsl.conf
# 以下の内容を設定(既存の内容があれば上書き) [interop] enabled = true appendWindowsPath = false
2. WSLのシャットダウンと再起動:
# PowerShellまたはコマンドプロンプトで実行 PS> wsl --shutdown
3. WSLを再起動:
- 再度開くWSLのディストリビューションを起動する。ターミナルを開くというのでも大丈夫です。
4. 設定の確認:
# 設定が反映されているか確認 $ cat /etc/wsl.conf # PATHにWindowsのパスが含まれていないことを確認(```mnt```が入っているとWindowsのバイナリが動く設定です) $ echo $PATH | tr ':' '\n' | grep '^/mnt'
この設定で、WSL環境内でのコマンド実行時にWindows側のプログラムが優先されることを防ぐことができます。
おまけ
Node.js
とnpm
のチェック用のスクリプトになります。
確認するプログラムを変更すれば、他でも使えるかもしれません。
check_environment.sh
#!/bin/bash # check_environment.sh echo "開発環境チェックを開始します..." # 1. Node.jsとnpmの場所チェック echo "=== Node.js/npm パスチェック ===" NODE_PATH=$(which node) NPM_PATH=$(which npm) echo "Node.js: $NODE_PATH" echo "npm: $NPM_PATH" # Windows パスチェック if echo "$NODE_PATH" | grep -q "/mnt/c/" || echo "$NPM_PATH" | grep -q "/mnt/c/"; then echo "警告: Windows側のNode.js/npmが使用されています" echo " × npm path: $NPM_PATH" echo "対策: 'sudo apt install nodejs npm' を実行してWSL側にインストールしてください" exit 1 fi # 2. バージョン情報の表示 echo -e "\n=== バージョン情報 ===" echo "Node.js: $(node -v)" echo "npm: $(npm -v)" echo -e "\n✅ すべてのチェックが完了しました"
おわりに
WSL環境でnpm
を実行した際に予期せずWindows側のパスを参照するという問題に出会いました。WSLとWindowsの相互運用性には便利な面がある一方で、予期せぬ動作を引き起こす可能性もありそうです。実行されるバイナリのPATHを明示的にしないとやばい自体になるかもしれません。whichコマンド
によるPATHの確認や、場合によっては/etc/wsl.conf
を編集することも検討したほうがいいのかもしれません。
一番簡単な方法は、WindowsネイティブにWSLで使用するようなバイナリをインストールせず、WSLやDocker
などを使用するということかもしれません🤔