RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/App Dev
App Dev/2026-06-07Intermediate

expo start --offline Says 'forbidden'? Corporate Proxy (403) vs Dependency Validation

Two different failures make 'expo start --offline' or EXPO_OFFLINE=1 die with 'forbidden': an HTTP 403 from a corporate proxy, and Expo CLI validateDependenciesVersions guard. How to tell them apart, when to set HTTP_PROXY to route through the proxy, and when to go fully offline with pre-generated caches instead.

expo11expo-clioffline-modedependency-validationcorporate-proxytroubleshooting65

You sit down in a weak-Wi-Fi cafe, fire expo start --offline, and Expo refuses:

validateDependenciesVersions cannot be disabled in this environment

Or you try EXPO_OFFLINE=1 expo start and it comes back with forbidden. The whole point of offline mode is to skip the npm registry round-trip, and the thing blocking it is a dependency-version check that needs… the registry. It is a small loop of frustration.

As an indie developer running an app business since 2014, with wallpaper apps that have crossed 50M cumulative downloads, I now use Rork in new projects layered onto that older app business — and I have hit this in airports, hotels, and onsite while preparing exhibitions abroad. The error has three intertwined causes, not one. Here is the diagnostic order that has reliably gotten me back to coding.

First, which forbidden is this — a proxy 403 or the CLI guard?

The same word forbidden covers two completely different failures, and telling them apart first saves you from applying the wrong fix.

  • An HTTP 403 from a corporate proxy or firewall. On a company or campus network, the proxy can reject the signed-manifest and version-check requests expo start makes in the background, returning 403 Forbidden. If the message includes request failed, 403, ECONNREFUSED, or your proxy hostname, this is your case.
  • Expo CLI own guard. If it spells out Setting EXPO_NO_DEPENDENCY_VALIDATION ... is forbidden in this environment, that is the validateDependenciesVersions story covered below.

Get the detailed log first:

EXPO_DEBUG=1 expo start --offline --verbose 2>&1 | tee /tmp/expo-start.log
grep -iE "403|forbidden|proxy|ECONN" /tmp/expo-start.log

If it is a proxy 403: route through the proxy, or go fully offline

You have two clean options.

A. Stay online, but go through the proxy. Expo CLI reads the HTTP_PROXY / HTTPS_PROXY environment variables and sends every network request through that proxy (internally via Undici EnvHttpProxyAgent). Point npm at the same proxy so installs do not stall either.

export HTTP_PROXY="http://user:pass@proxy.example.com:8080"
export HTTPS_PROXY="http://user:pass@proxy.example.com:8080"
npm config set proxy "http://user:pass@proxy.example.com:8080"
npm config set https-proxy "http://user:pass@proxy.example.com:8080"
 
expo start

B. Never touch the network at all. If the CLI makes no requests, the proxy cannot 403 you. EXPO_OFFLINE=1 (or --offline) stops Expo from making network calls, including manifest signing and version checks — but generate the first-run caches once on an unrestricted network beforehand (see the pre-caching section below).

EXPO_OFFLINE=1 expo start --offline

Use A for day-to-day work on the corporate network, B for planes and venues where the proxy is not reachable. --tunnel cannot run offline, so it is not the answer here.

If clearing the proxy 403 still leaves a separate validateDependenciesVersions cannot be disabled, that is the CLI guard — work through the three knobs next.

The three knobs that decide whether offline actually works

This is rarely a single-cause failure. It happens when all three of the following are wrong at once:

  1. Expo CLI version is on SDK 50 or later — before 50, offline mode bypassed this validation; after 50 it became mandatory by default
  2. No install.exclude block in package.json's expo field — there are packages in conflict and none are excused
  3. EXPO_OFFLINE is not actually reaching process.env — usually a shell quoting or shell-type issue

I have hit all three at the same time during one trip and lost a full afternoon to it.

1. Confirm your Expo CLI version

npx expo --version
# e.g., 0.18.21
cat package.json | grep '"expo":'
# e.g., "expo": "~50.0.6"

If you are pre-SDK-50, the cause is probably something else (network reachability or a registry timeout) — fix differently.

2. Configure install.exclude

Add an expo.install.exclude block to package.json:

{
  "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"
      ]
    }
  }
}

List the specific packages that conflict, not every dependency. Reanimated and expo-image are the two that come up most often in the wallpaper apps I work on.

3. Make sure the env var actually arrives

Inline env vars are not portable across shells. Verify:

EXPO_OFFLINE=1 expo start --offline
 
env | grep EXPO_OFFLINE
# should print EXPO_OFFLINE=1

Fish shell and Windows PowerShell do not accept the VAR=value command form. On PowerShell:

$env:EXPO_OFFLINE = "1"
npx expo start --offline

Long-term fix is cross-env in your package.json so the same script works on all three platforms:

{
  "scripts": {
    "start:offline": "EXPO_OFFLINE=1 expo start --offline",
    "start:offline:win": "cross-env EXPO_OFFLINE=1 expo start --offline"
  }
}

4. Wipe the caches

Metro can carry stale validation rules across runs. After the above is set:

rm -rf node_modules/.cache/metro
rm -rf /tmp/metro-*
rm -rf node_modules/.cache/expo
 
EXPO_OFFLINE=1 expo start --offline --clear

The --clear flag wipes Metro's bundle cache at startup. Combined with EXPO_OFFLINE=1, this is what gets the validation flag to actually behave.

5. If it still says forbidden, the CLI itself may be the bug

I have seen Expo CLI 0.18.16 silently fail to honor the disable flag, with 0.18.21 fixing it days later. If you are stuck after all of the above:

npx expo@latest --version
npm install expo@latest

The pattern I've noticed: in the first 1–2 weeks after a minor SDK release (SDK 51.0.0 was a recent example), validation-flag bugs are more common, then they get fixed quickly.

Three real conflict examples from my project

For reference, three concrete dependency conflicts that have actually blocked me with validateDependenciesVersions:

First, react-native-reanimated against Expo SDK pinning. Right after SDK 50 dropped, Reanimated 3.6.2 was a hair off from SDK's recommended 3.6.0. Added Reanimated to install.exclude; it resolved by itself when 3.6.3 came out.

Second, expo-image vs. native Glide pinning. My ad SDK pins Glide for AdMob compatibility; expo-image wanted a newer Glide. Same fix — exclude expo-image.

Third, and the one that cost the most time: dev-client vs production SDK drift. My EAS-built dev-client was on SDK 50.0.6 while my local package.json had drifted to 50.0.10. install.exclude doesn't fix this — you have to realign your local package.json to the dev-client's exact version. I now keep a comment in .eas/build-profile.json reading "dev-client = expo@50.0.6" and a rule to update both together.

Pre-caching for travel

To stop hitting this on the road, I added an offline-prep step at home before any trip:

# At home, online
expo install --check
git stash
zip -r wallpaper-rork-app-cached.zip . -x ".git/*"

On the trip, unzipping that bundle and running EXPO_OFFLINE=1 expo start --offline works fully offline, validation and all. I learned this the hard way during a week of exhibition prep abroad where the venue Wi-Fi was unusable — the pre-baked bundle is what saved that project.

Diagnostic checklist

The order I now run through before any trip:

  • [ ] npx expo --version shows 0.18.21 or newer
  • [ ] Conflicting packages added to expo.install.exclude
  • [ ] env | grep EXPO_OFFLINE confirms the variable is set
  • [ ] cross-env is in place if I'll be on Windows
  • [ ] Cleared node_modules/.cache/metro and ran with --clear
  • [ ] If still failing, Expo CLI bumped to the latest patch

In my own runs, this list resolves the validateDependenciesVersions blocker in ≥95% of attempts. The remaining few are usually a CLI-side patch issue that fixes itself within a week or two.

Offline mode is supposed to be the answer when networks are flaky. Watching the offline switch itself refuse to work is painful — I hope this saves someone else a flight's worth of debugging.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

App Dev2026-06-21
Your List Jumps Back to the Top — Restoring Scroll Position Across Back Navigation and Process Death
How I rebuilt scroll restoration for a wallpaper grid by splitting it into two unrelated problems — back navigation and process death — covering getItemLayout, save timing, and killing the restore flicker.
App Dev2026-05-31
Fixing the 'Signed With the Wrong Key' Error When Uploading a Rork App to Google Play
Your Rork app builds fine but Google Play rejects the upload with 'signed with the wrong key'? Here's how to tell which signing key is involved and the exact steps to fix it for each build setup.
App Dev2026-04-09
Fix Rork Android Build Errors: Gradle & SDK Troubleshooting Guide
Struggling with Android build errors in your Rork app? This guide covers the most common Gradle errors, SDK version mismatches, and memory issues — with step-by-step solutions for each.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →