Skip to main content

Appendix A

🐛 Common Errors and Solutions

Quick fixes for the most frequent React Native and Expo issues

Red Box Errors

Red box errors appear when there's a JavaScript exception. Here are the most common ones:

❌ "Text strings must be rendered within a <Text> component"

Cause: Raw text outside of a Text component

// ❌ Wrong
<View>
  Hello World
</View>

// ✅ Correct
<View>
  <Text>Hello World</Text>
</View>

Also check: Conditional rendering that might render empty strings or whitespace.

// ❌ Can cause issues
<View>
  {condition && 'Some text'}
</View>

// ✅ Safer
<View>
  {condition && <Text>Some text</Text>}
</View>

❌ "Cannot read property 'X' of undefined"

Cause: Accessing properties on undefined objects, often from API responses or navigation params

// ❌ Unsafe
const name = user.profile.name;

// ✅ Safe with optional chaining
const name = user?.profile?.name;

// ✅ Safe with default value
const name = user?.profile?.name ?? 'Unknown';

❌ "Invariant Violation: View config getter callback..."

Cause: Using a component that isn't properly imported or doesn't exist

// ❌ Wrong import
import { Button } from 'react-native'; // Button exists but check spelling

// ❌ Typo in component name
<Veiw></Veiw>

// ✅ Correct
import { View, Button } from 'react-native';
<View></View>

❌ "Objects are not valid as a React child"

Cause: Trying to render an object directly

// ❌ Wrong - rendering object
const user = { name: 'John', age: 30 };
<Text>{user}</Text>

// ✅ Correct - render specific properties
<Text>{user.name}</Text>

// ✅ Or stringify for debugging
<Text>{JSON.stringify(user, null, 2)}</Text>

❌ "Each child in a list should have a unique 'key' prop"

Cause: Missing or duplicate keys in lists

// ❌ Wrong - no key
{items.map(item => <Text>{item.name}</Text>)}

// ❌ Wrong - using index as key (can cause issues)
{items.map((item, index) => <Text key={index}>{item.name}</Text>)}

// ✅ Correct - unique identifier
{items.map(item => <Text key={item.id}>{item.name}</Text>)}

Metro Bundler Issues

⚠️ "Unable to resolve module" or "Module not found"

Solutions (try in order):

  1. Clear Metro cache and restart:
    npx expo start -c
  2. Delete node_modules and reinstall:
    rm -rf node_modules
    npm install
  3. Check the import path is correct (case-sensitive on some systems)
  4. Verify the package is installed:
    npm list package-name

⚠️ Metro bundler stuck or not updating

Solutions:

  1. Press r in terminal to reload
  2. Shake device and select "Reload"
  3. Stop Metro and restart with cache clear:
    # Stop with Ctrl+C, then:
    npx expo start -c
  4. Clear watchman (if installed):
    watchman watch-del-all

⚠️ "ENOSPC: System limit for number of file watchers reached"

Cause: Linux/WSL file watcher limit too low

Solution:

# Temporary fix
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Or edit /etc/sysctl.conf directly and add:
fs.inotify.max_user_watches=524288

⚠️ Port 8081 already in use

Solutions:

# Find and kill the process using port 8081
# On macOS/Linux:
lsof -i :8081
kill -9 <PID>

# Or use a different port:
npx expo start --port 8082

Native Dependency Problems

🔧 "Invariant Violation: Native module cannot be null"

Cause: Native module not linked or app not rebuilt

Solutions:

  1. For Expo managed projects, check if the module requires a development build:
    # Create a development build
    npx expo install expo-dev-client
    npx expo run:ios  # or run:android
  2. For bare projects, rebuild:
    # iOS
    cd ios && pod install && cd ..
    npx react-native run-ios
    
    # Android
    npx react-native run-android

🔧 iOS Pod Install Failures

Common fixes:

# Update CocoaPods
sudo gem install cocoapods

# Clear pod cache
cd ios
pod cache clean --all
rm -rf Pods Podfile.lock
pod install --repo-update
cd ..

🔧 Android Gradle Build Failures

Common fixes:

# Clean Gradle cache
cd android
./gradlew clean
cd ..

# Clear Gradle cache completely (more thorough)
rm -rf ~/.gradle/caches/

# Check Java version (React Native requires JDK 17)
java -version

🔧 "Duplicate class" or "Duplicate resources" on Android

Solution: Add to android/app/build.gradle:

android {
    packagingOptions {
        pickFirst 'lib/x86/libc++_shared.so'
        pickFirst 'lib/x86_64/libc++_shared.so'
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
    }
}

Build Errors

🏗️ EAS Build Failures

Common causes and solutions:

  • SDK version mismatch: Ensure all expo packages match your SDK version
    npx expo install --fix
  • Missing credentials: Run credentials setup
    eas credentials
  • Check build logs: Always read the full error log in the EAS dashboard

🏗️ "SDK version not supported"

Solution: Update to a supported SDK version:

# Check current version
grep "expo" package.json

# Upgrade SDK
npx expo install expo@latest

# Fix dependencies
npx expo install --fix

🏗️ iOS Signing Issues

Solutions:

  • For development: Use EAS to manage credentials automatically
    eas build --platform ios --profile development
  • Check Apple Developer account has active membership
  • Ensure correct bundle identifier in app.json

Runtime Errors

🔄 Infinite Re-render Loop

Cause: State updates in render or missing useEffect dependencies

// ❌ Wrong - causes infinite loop
function BadComponent() {
  const [count, setCount] = useState(0);
  setCount(count + 1); // Called every render!
  return <Text>{count}</Text>;
}

// ❌ Wrong - effect runs infinitely
useEffect(() => {
  setData(fetchData());
}); // Missing dependency array!

// ✅ Correct
useEffect(() => {
  setData(fetchData());
}, []); // Empty array = run once

🔄 "Can't perform state update on unmounted component"

Cause: Async operation completing after component unmounts

// ✅ Solution with cleanup
useEffect(() => {
  let isMounted = true;
  
  async function fetchData() {
    const result = await api.getData();
    if (isMounted) {
      setData(result);
    }
  }
  
  fetchData();
  
  return () => {
    isMounted = false;
  };
}, []);

// ✅ Or use AbortController for fetch
useEffect(() => {
  const controller = new AbortController();
  
  fetch(url, { signal: controller.signal })
    .then(res => res.json())
    .then(setData)
    .catch(err => {
      if (err.name !== 'AbortError') throw err;
    });
  
  return () => controller.abort();
}, [url]);

🔄 Navigation: "The action 'NAVIGATE' was not handled"

Cause: Trying to navigate to a screen that doesn't exist in current navigator

// Check that:
// 1. Screen name matches exactly (case-sensitive)
// 2. Screen is defined in the navigator
// 3. You're using the correct navigation method

// For nested navigators:
navigation.navigate('ParentStack', {
  screen: 'ChildScreen',
  params: { id: 123 }
});

🔄 FlatList: Items not updating

Cause: FlatList not detecting data changes

// ❌ Problem: mutating array doesn't trigger update
items.push(newItem);
setItems(items);

// ✅ Solution: create new array reference
setItems([...items, newItem]);

// ✅ Or use extraData prop
<FlatList
  data={items}
  extraData={selectedId} // Re-render when this changes
  renderItem={renderItem}
/>

Expo-Specific Issues

📱 "This app cannot be run in Expo Go"

Cause: Using a package that requires custom native code

Solution: Create a development build:

# Install dev client
npx expo install expo-dev-client

# Build for your device
eas build --profile development --platform ios
# or
eas build --profile development --platform android

# Or run locally
npx expo run:ios
npx expo run:android

📱 Expo Go not connecting to development server

Solutions:

  1. Ensure phone and computer are on same WiFi network
  2. Try tunnel mode:
    npx expo start --tunnel
  3. Check firewall isn't blocking port 8081
  4. Try manual URL entry in Expo Go

📱 Assets not loading

Solutions:

// Ensure correct path (from project root)
<Image source={require('./assets/image.png')} />

// For dynamic images, use asset modules
import { Asset } from 'expo-asset';

// Preload assets
await Asset.loadAsync([
  require('./assets/image.png'),
]);

📱 "Unmatched route"

Cause: Expo Router can't find the route file

Check:

  • File exists in app/ directory
  • File name matches expected route
  • File has a default export
  • No syntax errors in the file

Debugging Strategies

🔍 General Debugging Workflow

  1. Read the error message carefully - it often tells you exactly what's wrong
  2. Check the component stack - find which component caused the error
  3. Add console.log statements - track data flow
  4. Use React DevTools - inspect component props and state
  5. Check recent changes - what did you change before it broke?
  6. Search the error - someone else has probably encountered it

🔍 Using Console Logs Effectively

// Label your logs
console.log('User data:', userData);
console.log('Before API call');
console.log('After API call, response:', response);

// Use console.table for arrays/objects
console.table(items);

// Use console.group for related logs
console.group('Render cycle');
console.log('Props:', props);
console.log('State:', state);
console.groupEnd();

// Trace where something is called from
console.trace('This function was called');

🔍 React DevTools

Setup:

# Install standalone DevTools
npm install -g react-devtools

# Run DevTools
react-devtools

# Then start your app
npx expo start

Features:

  • Inspect component hierarchy
  • View and edit props/state
  • Track component renders
  • Profile performance

🔍 Network Debugging

// Add request/response logging
const originalFetch = global.fetch;
global.fetch = async (...args) => {
  console.log('Fetch request:', args);
  const response = await originalFetch(...args);
  console.log('Fetch response:', response.status);
  return response;
};

// Or use Flipper for comprehensive network debugging

✅ Prevention Checklist

  • ☐ Use TypeScript for type safety
  • ☐ Add ESLint with React Native rules
  • ☐ Write tests for critical paths
  • ☐ Use optional chaining (?.) for object access
  • ☐ Always handle loading and error states
  • ☐ Keep dependencies updated
  • ☐ Test on both iOS and Android regularly

Quick Reference Commands

🚀 Common Fix Commands

# Clear everything and start fresh
rm -rf node_modules
rm -rf .expo
npm install
npx expo start -c

# iOS specific
cd ios && pod install --repo-update && cd ..

# Android specific
cd android && ./gradlew clean && cd ..

# Reset Metro bundler
npx expo start -c

# Fix Expo package versions
npx expo install --fix

# Check for issues
npx expo-doctor