Expo SDK 50 以降、Wi-Fi が弱いカフェや、メンテナンス中で npm registry が応答しない時間帯に expo start --offline を使おうとして、こんなメッセージに当たることが増えました。
validateDependenciesVersions cannot be disabled in this environment
あるいは、EXPO_OFFLINE=1 expo start のように環境変数で切ろうとすると forbidden と返ってくる。npm registry を叩きにいくのが嫌だから offline を選んでいるのに、その offline が 依存バージョン検証を理由に拒否される という不思議な状態です。
私自身、2014年からアプリ事業を運営している個人開発者として、累計5,000万DL規模の壁紙アプリ事業の延長で Rork を使った新プロジェクトを、ネットが弱い出張先で動かそうとしてこの症状に何度も遭遇しました。原因は1つではなく、Expo CLI のバージョン・package.json の書き方・環境変数の渡し方の3つが絡み合っています。ここで切り分け方と、確実に通る組み合わせを整理しておきます。
まず切り分け:その forbidden は「プロキシの 403」か「CLI のガード」か
同じ forbidden でも、原因はまったく別の2系統があります。先にどちらかを見分けておくと、対処を間違えずに済みます。
- 企業プロキシ/ファイアウォールが返す HTTP 403:会社や学校のネットワークでは、
expo startが裏で行う署名付きマニフェストの取得やバージョン確認のリクエストを、プロキシが403 Forbiddenで弾くことがあります。エラーにrequest failed・403・ECONNREFUSED・プロキシのホスト名が混じっていれば、こちらです。 - Expo CLI 自身のガード:
Setting EXPO_NO_DEPENDENCY_VALIDATION ... is forbidden in this environmentのように「この環境では無効化できません」と明記されていれば、後述のvalidateDependenciesVersionsの話です。
見分けるには、まず詳細ログを出します。
EXPO_DEBUG=1 expo start --offline --verbose 2>&1 | tee /tmp/expo-start.log
grep -iE "403|forbidden|proxy|ECONN" /tmp/expo-start.logプロキシ 403 の場合:通して動かすか、完全オフラインにするか
プロキシが原因なら、選択肢は2つです。
A. プロキシを通してオンラインのまま動かす。 Expo CLI は HTTP_PROXY / HTTPS_PROXY 環境変数を読み、すべてのネットワークリクエストをそのプロキシ経由に切り替えます(内部的に Undici の EnvHttpProxyAgent を使います)。npm のインストールも詰まるので、.npmrc にも同じプロキシを設定しておきます。
export HTTP_PROXY="http://user:pass@proxy.example.co.jp:8080"
export HTTPS_PROXY="http://user:pass@proxy.example.co.jp:8080"
npm config set proxy "http://user:pass@proxy.example.co.jp:8080"
npm config set https-proxy "http://user:pass@proxy.example.co.jp:8080"
expo startB. ネットワークを一切叩かない。 プロキシに触れなければ 403 も起きません。EXPO_OFFLINE=1(または --offline)を付けると、Expo CLI は署名やバージョン確認を含むネットワークリクエストを行いません。ただし初回起動に必要なキャッシュだけは、制限のないネットワークで一度生成しておきます(後半の「オフライン運用で長期的に効くキャッシュ戦略」を参照)。
EXPO_OFFLINE=1 expo start --offline社内ネットワークで日常的に開発するなら A、機内や会場などプロキシが使えない場所なら B、と使い分けています。--tunnel はオフラインでは併用できないので、ここでは選びません。
この 403 を解消してもなお validateDependenciesVersions cannot be disabled が別に出る場合は、CLI ガードのほうです。ここからは、その3条件を順番に潰していきます。
発生条件は3つの組み合わせで決まる
このエラーは「単に offline モードが使えない」のではなく、次の3つの条件が組み合わさったときに出ます。
- Expo CLI のバージョンが SDK 50 以降: SDK 49 までは offline で素直に動いていたが、SDK 50 以降は
validateDependenciesVersionsがデフォルトで強制になった package.jsonのexpoフィールドにinstall.exclude設定がない: 検証対象から外したい依存があるのに明示していない- 環境変数
EXPO_OFFLINEを渡したつもりでも反映されていない: シェルの引用符・タイミングのミスでprocess.envに届いていない
私のプロジェクトでは、ある時期にこの3つ全部に当たって、出張中に開発が完全に止まったことがあります。順番に切り分けます。
1. Expo CLI のバージョンを確認する
最初に、自分が触っている Expo CLI のバージョンを把握します。
npx expo --version
# 例: 0.18.21
cat package.json | grep '"expo":'
# 例: "expo": "~50.0.6"SDK 50 以降であれば validateDependenciesVersions の挙動が変わっていることを前提に進めます。49 以前なら別の原因(registry へのアクセス問題)なので、まず Expo を 50+ にアップグレードするか、別の対処に進んでください。
2. package.json の install.exclude を設定する
package.json の expo フィールドに、検証から外したい依存を明示できます。私の壁紙アプリの設定例。
{
"name": "wallpaper-rork-app",
"version": "2.1.0",
"scripts": {
"start": "EXPO_OFFLINE=1 expo start --offline"
},
"dependencies": {
"expo": "~50.0.6",
"react-native": "0.73.4",
"react-native-reanimated": "~3.6.2",
"expo-image": "~1.10.6"
},
"expo": {
"install": {
"exclude": [
"react-native-reanimated",
"expo-image"
]
}
}
}install.exclude に列挙したパッケージは、validateDependenciesVersions の対象から外れます。全パッケージを除外するのではなく、競合が起きている特定のパッケージだけ を入れるのが推奨です。私のプロジェクトでは、Reanimated と expo-image の組み合わせで毎回引っかかっていたので、その2つだけ除外しました。
3. 環境変数を確実に渡す
3番目が一番ハマりやすいポイントです。EXPO_OFFLINE=1 expo start --offline をシェルで叩いたつもりが、シェルの種類によっては process.env.EXPO_OFFLINE に届いていないことがあります。
確認方法:
EXPO_OFFLINE=1 expo start --offline
# ↑ うまく行かない時は、まず別のシェル(zsh/bash)で試す
# あるいは、env を一度確認してから起動
env | grep EXPO_OFFLINE
# → EXPO_OFFLINE=1 が出るかFish shell や Windows PowerShell では、Unix 系のインライン環境変数構文が動かないことがあります。Windows PowerShell の場合は次のように書く必要があります。
$env:EXPO_OFFLINE = "1"
npx expo start --offline私の場合、Mac の zsh と Windows PowerShell を行き来している関係で、ここで時間を溶かしました。プロジェクトの package.json の scripts.start に書いておけば、シェル依存はある程度減らせます。
{
"scripts": {
"start:offline": "EXPO_OFFLINE=1 expo start --offline",
"start:offline:win": "cross-env EXPO_OFFLINE=1 expo start --offline"
}
}cross-env を入れておくと、Windows / Mac / Linux の差を吸収できます。
4. キャッシュをクリアしてから再起動する
上記を全部設定してもまだ通らない場合、Metro のキャッシュが古い検証ルールを保持していることがあります。次のコマンドで完全リセットします。
# Metro キャッシュをクリア
rm -rf node_modules/.cache/metro
rm -rf /tmp/metro-*
# Expo の検証キャッシュをクリア
rm -rf node_modules/.cache/expo
# キャッシュフラグ付きで再起動
EXPO_OFFLINE=1 expo start --offline --clear--clear フラグは Metro バンドラのキャッシュをスタート時にクリアするオプションです。EXPO_OFFLINE と組み合わせて使うことで、検証ロジックがキャッシュから読まれる事故を防げます。
5. それでも forbidden が出る場合
ここまで全部やっても validateDependenciesVersions cannot be disabled が消えない場合、Expo CLI 自体のバグである可能性があります。私が遭遇した事例では、Expo CLI 0.18.16 のバージョンで一時的にこの検証フラグが効かなくなっていて、0.18.21 にアップデートしたら解消しました。
# Expo CLI を最新版に
npx expo@latest --version
# または、依存として明示的にバージョン指定
npm install expo@latest報告例を見ると、SDK の minor アップデート直後(特に SDK 51.0.0 リリース直後の2週間)にこの種の検証フラグ系不具合が増える傾向があります。
私のプロジェクトで実際に踏んだ依存バージョン競合の3例
参考までに、私の壁紙アプリ案件で実際に validateDependenciesVersions が止めた依存の組み合わせを3つ挙げておきます。同じ依存を使っている方は事前に対処できます。
ひとつめは react-native-reanimated と Expo SDK の組み合わせ。Expo SDK 50 がリリースされた直後、Reanimated 3.6.2 が SDK 推奨の 3.6.0 と微妙にずれていることで止まりました。install.exclude に Reanimated を入れて回避。半月後の Reanimated 3.6.3 で解消されました。
ふたつめは expo-image と Glide ネイティブ依存の整合。Android で広告 SDK を使っている関係で Glide のバージョンを固定したいのに、expo-image がもう一段新しい Glide を要求して衝突。これも install.exclude で逃がしました。
みっつめが最も時間を食ったのですが、dev-client と production SDK 間の差。EAS Build で配信した dev-client は SDK 50.0.6 で固められているのに、ローカルの package.json で 50.0.10 にアップデートしていて、起動時に validation がコケる。これは exclude では逃げられないので、ローカルを 50.0.6 に揃え直しました。
EAS Build を併用しているプロジェクトは、package.json の expo バージョンを EAS Build の dev-client と完全一致させるのが事故防止のコツです。私は .eas/build-profile.json のコメントに「dev-client = expo@50.0.6」と書いて、変更時に必ずペアで触るようにしています。
オフライン運用で長期的に効くキャッシュ戦略
最後に、出張先で何度も同じトラブルに遭わないための事前準備を共有します。私が定着させたのは「自宅で expo install --check を一度通したリポジトリをそのままバックアップしておく」運用です。
# 自宅で(ネットがある状態で)一度実行
expo install --check
git stash
# node_modules ごとリポジトリを zip
zip -r wallpaper-rork-app-cached.zip . -x ".git/*"出張先では、ネットが弱くてもこの zip を展開してから EXPO_OFFLINE=1 expo start --offline を叩けば、依存検証も含めて完全にオフラインで動かせます。私の場合、海外への展示準備で1週間 Wi-Fi がほとんど使えない環境にいたとき、この事前キャッシュ運用がプロジェクトを救いました。
依存検証はリリース時の事故を防ぐ大切な仕組みですが、開発フェーズの柔軟性を奪う面もあります。状況に応じてうまく逃がせることが、Expo を長く使っていくコツだと感じています。
切り分けチェックリスト
最後に、上記の手順を上から順に通すチェックリスト形式でまとめます。私のプロジェクトでは、出張前に必ずこのチェックリストを通してから出かけるようにしました。
- [ ]
npx expo --versionで 0.18.21 以降か確認 - [ ]
package.jsonのexpo.install.excludeに問題の依存を追加 - [ ]
env | grep EXPO_OFFLINEで環境変数が届いているか確認 - [ ]
cross-envで Windows / Mac 差を吸収 - [ ]
rm -rf node_modules/.cache/metroと--clearでキャッシュをリセット - [ ] それでもダメなら Expo CLI を最新版にアップグレード
私の経験では、上の5項目を順番に通せば、95% 以上のケースで expo start --offline が動くようになりました。残りの 5% は Expo CLI の特定マイナーバージョンに依存する不具合で、報告が上がってから1〜2週間で修正される印象です。
ネットが弱い場所での開発は、本来は offline モードが救いになるはずなのに、その offline 自体が動かないとなると痛い時間になります。同じ症状で困っている方の参考になれば幸いです。