Skip to content

Troubleshooting & Diagnostics Guide

Common Issues, Expo SDK 57 Nuances, Permissions, and Hardware Diagnostics

This guide outlines common errors, hardware lifecycle caveats, and resolution steps for PixelKit developers.


  1. KeepAwake Tag Error in Expo SDK 57
  2. StatusBar BackgroundColor Deprecation
  3. Camera Permission & Simulator Fallback
  4. ADPF Thermal Throttling Mitigation
  5. Hermes Bytecode Metro Bundling Verification
  6. Keystore and SecureStore access modes
  7. A hook returns null and its source says unavailable

Unhandled promise rejection: activateKeepAwake requires a tag parameter in Expo SDK 57.

In Expo SDK 57 (~57.0.20), activateKeepAwakeAsync() requires passing a string tag to identify the wake-lock owner.

Always pass a unique tag when activating or deactivating:

import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake';
const TAG = 'pixelkit_display_lock';
// CORRECT
await activateKeepAwakeAsync(TAG);
deactivateKeepAwake(TAG);
// WRONG (Omitted tag throws in Expo 57)
await activateKeepAwakeAsync();

TypeScript warning or runtime error: Property 'backgroundColor' does not exist on type 'IntrinsicAttributes & StatusBarProps'.

In Expo SDK 57, <StatusBar /> from expo-status-bar dropped the backgroundColor prop in favor of root View background styling.

Style the parent <SafeAreaView> or root <View> with Colors.dark.background (#0E1119) and use <StatusBar style="light" />:

<SafeAreaView style={{ flex: 1, backgroundColor: '#0E1119' }}>
<StatusBar style="light" />
{/* Content */}
</SafeAreaView>

Camera screen throws Camera permission not granted on Android emulator or initial launch.

useCamera() includes an asynchronous permission check with a graceful fallback. Ensure app.json includes the camera permission:

"android": {
"permissions": [
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO"
]
}

If running in an emulator without camera hardware, useVisionAI() provides gallery photo picking via captureAndAnalyze(false).


Frame drops or stutter when rendering complex graphics or processing sustained neural workloads.

Check useADPF().thermalStatus:

const { thermalStatus } = useADPF();
if (thermalStatus === 'severe' || thermalStatus === 'critical') {
// 1. Back off sensor polling to 500ms
// 2. Pause non-essential background tensor passes
// 3. Extinguish flashlight / HiLight ring
}

5. Hermes Bytecode Metro Bundling Verification

Section titled “5. Hermes Bytecode Metro Bundling Verification”

To ensure all TypeScript modules compile and package cleanly without syntax or bundling errors:

Terminal window
# 1. Typecheck
npm run typecheck
# 2. Bundle Hermes bytecode for Android
npx expo export -p android

If bundling reports an error, clean the Metro cache:

Terminal window
npx expo start -c

On Android, expo-secure-store encrypts values with a key held in the Android Keystore, StrongBox-backed on this device.

  • useSecurity().saveSecureItem(key, value) uses WHEN_UNLOCKED_THIS_DEVICE_ONLY, so a value is readable only while the device is unlocked and never leaves this phone.
  • On web there is no Keystore: the hook falls back to localStorage, which is not encrypted. isHardwareBacked is false there, so gate anything sensitive on it.
  • isPostQuantumProtected is always false. Android 17 defines post-quantum key types; SecureStore does not use them.

7. A hook returns null and its source says unavailable

Section titled “7. A hook returns null and its source says unavailable”

A metric renders as “—” and source is 'unavailable'.

This is the SDK working as designed, not a bug. There is no simulated provenance value: when a reading cannot be taken, the value is null rather than a plausible substitute. Common reasons:

Cause Check Fix
Running in Expo Go or on web PixelNative and PixelNano resolve to null there Use a development build on the device
Permission not granted hasPermission, permissionGranted, hasHardware on the hook Request it, then re-read
The device lacks the hardware useCapabilities()hasUWB, hasHiLight, hasStrongBox, hasNFC Hide the control rather than showing one that fails
The daemon is not running (HiLight only) availability === 'unavailable' npm run hilight:daemon
First sample has not arrived hasMotionSample, hasFix, hasRead, isReady Wait; render “—” meanwhile

Render null as “—”, pass source to MetricCard so the tag is visible, and read the hook’s error field for the reason. Never substitute a default.