You deploy your React Native app, run it on an Android emulator, and boom. The console spits out TypeError: Network request failed. Your API calls worked fine in Postman. They even worked on iOS. But Android decides to play hard to get. This error is one of the most frustrating blockers for React Native developers, especially when you are new to mobile development. The good news is that it almost always has a straightforward cause. Let me walk you through the usual suspects and show you exactly how to get your network requests back on track.
The ‘network request failed’ error in React Native on Android usually comes from one of four issues: missing internet permission in AndroidManifest.xml, blocked cleartext traffic on Android 9+, incorrect localhost address in the emulator, or SSL certificate mismatches. Fixing these covers 90% of cases. Always check your AndroidManifest and handle cleartext traffic properly for local development.
What Triggers “Network Request Failed” in React Native?
React Native uses the browser’s fetch API or a polyfill under the hood. When the request cannot complete for any reason, JavaScript throws TypeError: Network request failed. The error message is intentionally vague to avoid leaking internal details, but the root causes are well known in the community. Here is a breakdown of the most common triggers.
Missing Internet Permission (Android)
On Android, your app must explicitly request network access. If you forget to add the internet permission to AndroidManifest.xml, all HTTP and HTTPS requests will fail silently. This is the number one cause for beginners.
Open your project’s android/app/src/main/AndroidManifest.xml and check for this line near the top, inside the <manifest> tag but outside <application>:
<uses-permission android:name="android.permission.INTERNET" />
If it is missing, add it. Rebuild the app. That often solves the problem.
Cleartext Traffic Blocked on Android 9 and Later
Starting with Android 9 (API level 28), cleartext traffic (HTTP) is blocked by default. If your local development server uses HTTP, your requests will fail unless you explicitly allow it. Even when connecting to an HTTPS API on a physical device, you might need a network security config for self-signed certificates during development.
Add a network_security_config.xml file inside android/app/src/main/res/xml/ (create the xml folder if needed) with the following content:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
</network-security-config>
Then reference it in AndroidManifest.xml inside the <application> tag:
<application
android:networkSecurityConfig="@xml/network_security_config"
...>
This tells Android to allow HTTP requests to your local development server without a valid certificate.
Wrong Localhost Address for Android Emulator
On iOS simulators, localhost or 127.0.0.1 works because the simulator shares the host machine’s network. Android emulators, however, run inside a virtual machine. localhost from the emulator refers to the emulator itself, not your development machine. Instead, use the special IP 10.0.2.2. That IP maps to the host machine’s loopback interface.
If your API base URL is hardcoded to http://localhost:3000, change it to http://10.0.2.2:3000. For physical devices connected via USB or Wi-Fi, use your computer’s local IP address (like 192.168.x.x). This is the most common trap for developers moving from web or iOS.
SSL Certificate Validation Errors
If your API uses HTTPS with a self-signed certificate (common in corporate or staging environments), Android will reject it by default. In production, you should use a valid certificate from a trusted authority. But for development, you can add a certificate pinning exception or trust user-installed certificates. The safest approach is to use a proper SSL certificate (e.g., from Let’s Encrypt) even for staging.
Proxy and Network Configuration
Sometimes the error stems from corporate proxies or VPNs interfering with traffic. Android emulators have their own proxy settings. You can configure the emulator’s proxy under Settings > Wi-Fi & internet > Proxy. Or set the HTTP_PROXY environment variable when launching the emulator.
Debugging the Error Step by Step
When you encounter the error, follow this numbered process. It covers the most common causes in order of likelihood.
- Check the AndroidManifest.xml for the internet permission. If missing, add it and rebuild.
- Look at your API request URL. Are you using
localhostfor the emulator? Replace it with10.0.2.2. For physical devices, use your computer’s LAN IP. - Enable cleartext traffic for development. Add the
network_security_config.xmlas described above. - Test with a simple fetch to a public HTTPS API (like
https://jsonplaceholder.typicode.com/todos/1). If that works, the problem is your specific server setup. If it fails, check your network connectivity inside the emulator. - Use the emulator’s browser to verify network. Open the Chrome app in the emulator and try to load your API URL. If the browser cannot load it, the issue is outside your React Native code.
- Inspect the actual error with a try/catch. Wrap your fetch call and log the error object. Sometimes it contains a
messageorcauseproperty with more details.
Common Mistakes and How to Fix Them
Here is a table that summarizes the most frequent mistakes and their solutions.
| Mistake | Why It Happens | Fix |
|---|---|---|
| Missing INTERNET permission | Forgot to add to AndroidManifest.xml | Add <uses-permission android:name="android.permission.INTERNET"/> |
| Using localhost in emulator | Assumes emulator shares host network | Use 10.0.2.2 for emulator, or your machine’s IP for physical devices |
| HTTP requests blocked on Android 9+ | Cleartext traffic disabled by default | Add network_security_config.xml and reference in manifest |
| Self-signed SSL certificate | Android does not trust it | Use a valid certificate or configure certificate pinning for development |
| Firewall blocking the emulator | Corporate network or VPN | Configure emulator proxy or use a different network |
Expert advice: Always test your React Native network requests with a real device connected via USB. Emulators can sometimes mask proxy or DNS issues that physical devices will surface. I have seen countless cases where the error only appeared on a physical Android phone after weeks of smooth sailing on the emulator.
Tools to Help Diagnose the Issue
Sometimes the built-in error message is not enough. Here are tools I use to get more insight.
- React Native Debugger — Opens Chrome DevTools along with your app’s network tab. You can inspect each request, see the headers, response, and error status.
- Flipper — A desktop debugging tool from Facebook that includes a network plugin. It shows all network requests and responses in real time.
- Charles Proxy or mitmproxy — Lets you capture all traffic from the emulator or device. You can see exactly what the app is sending and receiving, including SSL handshake errors.
- Android Studio Logcat — Filters by
ReactNativeorokhttpto see lower-level network errors from the native side. Sometimes the JavaScript error hides a more specific native exception. - Postman or curl — Use these to confirm the API is reachable from your development machine. If Postman works but the app does not, the issue is on the mobile side.
Platform-Specific Differences You Should Know
iOS and Android handle networking differently. Knowing these differences saves hours of debugging.
iOS Simulator
The iOS simulator is less strict. It allows HTTP by default, and localhost points to your Mac. No special configuration is needed. This is why many apps work on iOS but fail on Android.
Android Emulator
As mentioned, the emulator is a full VM. It uses its own network stack. The emulator can access the host via 10.0.2.2, and it has its own proxy settings. Also, the emulator may have slower DNS resolution or blocked ports depending on your host firewall.
Physical Android Device
When testing on a real phone, ensure both the phone and your development machine are on the same Wi-Fi network. Use the machine’s IP address (e.g., 192.168.1.10) instead of localhost. If you are using Expo, you can use expo start --tunnel to bypass network issues, but this adds overhead.
Handling Timeouts and Slow Networks
Even if the request is configured correctly, a timeout can produce the same “network request failed” error. React Native’s default fetch timeout is surprisingly long (about 5 minutes on Android), but poor network conditions can cause it to hang and eventually fail without a clear timeout error.
Set explicit timeouts using AbortController or a third-party library like axios. For example:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 seconds
fetch('https://api.example.com/data', { signal: controller.signal })
.then(response => response.json())
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request timed out');
} else {
console.error('Network request failed', error);
}
})
.finally(() => clearTimeout(timeoutId));
Using AbortController gives you control over network failures and allows you to retry intelligently.
When the Error Persists After All Fixes
If you have followed every step above and still see the error, consider these advanced checks.
- Check your API server’s CORS headers. React Native does enforce CORS, but only on certain native implementations. Sometimes a CORS failure is reported as a network error. Ensure your server includes
Access-Control-Allow-Origin: *or at least your app’s origin. - Inspect the native logs. Use Android Studio’s Logcat with the filter
ReactNative:JSand alsoOkHttp. The native HTTP layer may print a more specific error like “SSL handshake aborted” or “Connection refused”. - Test with a different network. Switch from Wi-Fi to mobile data on a physical device. Corporate networks often block unknown ports or HTTP traffic.
- Update React Native and its dependencies. In 2026, many older versions have unresolved networking bugs. Make sure you are on a recent stable release.
- Review your Android configurations for API level. If your app targets API level 28 or higher, the cleartext traffic restriction applies automatically. Check
build.gradlefortargetSdkVersion.
Build Resilience into Your Network Layer
Prevention is better than a fix. Once you have a working HTTP client, add retry logic with exponential backoff to handle transient failures. Use a library like react-native-retry or implement a simple wrapper around fetch. This way, occasional network hiccups do not crash your user’s experience.
async function fetchWithRetry(url, options, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
return response;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
}
}
}
Combine this with a global error handler that logs to a remote service. You can catch these errors and surface them to your team before users notice.
Keep Learning with Related Guides
If you enjoyed this deep dive, you might find these articles helpful for improving your debugging workflow:
- Learn some common JavaScript debugging tricks every developer should know to handle tricky issues.
- Understand how to avoid similar pitfalls in backend code by optimizing database calls to prevent backend performance bottlenecks.
- For frontend-specific tips, check out mastering debugging strategies for frontend JavaScript errors.
Your Network Requests Are Now Under Control
The “network request failed” error in React Native can feel like a brick wall, but it is almost always a configuration issue. Start with the internet permission, fix the localhost address for Android, allow cleartext traffic during development, and validate your SSL setup. That checklist will get you through 99% of cases. The next time you see that error, you will know exactly where to look. Keep your debugger open, your network_security_config.xml handy, and remember that every failed request is just a clue waiting to be followed. Go ahead and test those fixes now. Your app will thank you.
