-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Summary
Voltra’s config plugin breaks the standard Continuous Native Generation (CNG) workflow used by EAS Build. The plugin attempts to read the Live Activity extension’s Info.plist during config introspection, but this file doesn’t exist yet because prebuild hasn’t run.
This affects anyone following Expo’s recommended practice of gitignoring the ios/ directory and letting EAS Build generate it in the cloud.
The Problem
When running eas build (or the fingerprint-based continuous deployment action), EAS CLI runs config introspection locally before uploading your project:
Failed to read the app config from the project using "npx expo config" command:
npx expo config --json --type introspect exited with non-zero code: 1
During introspection, Voltra’s plugin calls readFileSync on ios/{AppName}LiveActivity/Info.plist:
[ios.infoPlist]: withIosInfoPlistBaseMod: ENOENT: no such file or directory,
open '/home/runner/work/.../ios/PUMPDLiveActivity/Info.plist'
Timeline of what happens:
- Developer runs
eas build(noios/folder exists - this is correct for CNG) - EAS CLI runs
npx expo config --type introspectlocally to read entitlements for credential generation - Voltra’s
withInfoPlistmod tries to readios/{App}LiveActivity/Info.plist - Build fails - the file won’t exist until prebuild runs on EAS’s macOS builders
Why This Violates Expo Plugin Guidelines
From Expo’s config plugin documentation:
“Generate, move, and delete new files in dangerous mods only. Failing to do so will break introspection.”
“Introspection only supports a subset of modifiers… Introspection only works on safe modifiers (static files like JSON, XML, plist, properties)”
The issue is in plugin/build/features/ios/plist/index.js - configureMainAppPlist uses withInfoPlist and reads a file that’s created by generateWidgetExtensionFiles (which uses withDangerousMod). The withInfoPlist mod runs during introspection, but withDangerousMod does not.
Current Workaround
Run npx expo prebuild --platform ios before eas build. However, this:
- Defeats the purpose of CNG (generating native code locally)
- Requires committing the extension folder or using
.easignoretricks - Adds complexity to CI pipelines
Suggested Fixes
Option 1: Guard the file read
const { existsSync, readFileSync } = require('fs');
if (existsSync(filePath)) {
const content = plist.parse(readFileSync(filePath, 'utf8'));
// ... rest of logic
} else {
// Skip during introspection, will run properly during actual prebuild
return config;
}Option 2: Follow the expo-apple-targets pattern
Keep extension source files (including Info.plist) in a /targets folder outside ios/, then symlink them during prebuild. This way the source files exist in the repo and can be read during introspection, without breaking CNG for the main app.
Option 3: Move file reads to withDangerousMod
Ensure all file reads happen in withDangerousMod callbacks that only execute during actual prebuild, not introspection.
Environment
- voltra: 1.1.2
- expo: SDK 52
- eas-cli: 16.32.0
- CI: GitHub Actions (Ubuntu) with
expo/expo-github-action/continuous-deploy-fingerprint
Reproduction
- Create an Expo project with Voltra configured
- Add
ios/to.gitignore(standard CNG setup) - Push to GitHub and run
eas build --platform ios - Build fails during config introspection