Troubleshooting

Most problems fall into one of three groups. Start with the one that matches what you’re seeing.

Find the right section

My build failed

My build worked, but the app doesn’t

Signing and store uploads

Certificates, provisioning profiles, keystores, APK vs AAB, and App Store Connect and Google Play upload errors have their own page: Signing and store upload problems.

Older projects (PhoneGap and older Cordova)

Still stuck? See What to send if you need help.

Start here: find the real error in your log

When a build fails, the message on the upload page is a summary. The cause is in the log.

  1. On the upload page, click View Log for the failed build.
  2. Search the log for error (or FAILURE for Android Gradle builds). The first error is usually the real one. Later errors are often side effects of it.
  3. Near the end of the log, check the list of plugins and their versions. If a plugin hasn’t been updated in years, it’s a likely cause, especially right after a new Android or iOS release.

Many errors include a link to a section of this site. Follow it first.

Most build failures we see are caused by one of the next four items: an unpinned engine, an unpinned plugin, a target SDK that doesn’t match the engine, or a broken edit-config. If your project “built fine last week” and you haven’t changed anything, it’s almost always the first two: a new version of the engine or a plugin was released, and your project picked it up automatically.

(Cordova projects. For Capacitor, versions come from your package.json. See Setting up your Capacitor project.)

Pin your engine versions

If your config.xml has no <engine> tag for a platform, every build uses the newest cordova-android or cordova-ios. When a new major version comes out, older plugins and settings can stop working overnight. Your log will show:

Warning! No Android engine specified. Defaulting to latest engine.

Pin exact versions:

<engine name="android" spec="14.0.1" />
<engine name="ios" spec="7.1.1" />

The versions we support, and the Java and SDK each one uses, are on Build environment. Engines below 10.0.0 are rejected, except for our cordova-android 9.1.1 fork described there.

Pinning doesn’t mean never upgrading. It means you upgrade when you choose to, and test when you do.

Pin your plugin versions

The same applies to plugins. A plugin line without a version gets the newest release on every build:

<plugin name="cordova-plugin-camera" />

Pin the version you’ve tested with:

<plugin name="cordova-plugin-camera" spec="8.0.0" />

To find the current version of a plugin, look it up on npmjs.com. When a build breaks after a plugin update, pin the previous version that worked, then look at the plugin’s changelog or issues before moving forward.

On the Free, Indy and Pro plans, spec must be a version from npm. Git URLs and local folders need an Enterprise plan. See Using Plugins.

If a plugin hasn’t been updated for a recent cordova-android or cordova-ios, it may not build at all. Check Is it a good plugin? before adding one, and look for a maintained fork or alternative if needed.

Match android-targetSdkVersion to your engine

Each cordova-android version supports one maximum Android SDK. Setting android-targetSdkVersion higher than your engine supports, or using plugins that need a newer SDK than your engine provides, fails the build.

cordova-android Highest target SDK
15.x 36
14.x 35
13.x 34
12.x 33
<engine name="android" spec="14.0.1" />
<preference name="android-targetSdkVersion" value="35" />

If you don’t set android-targetSdkVersion, the engine’s default is used. That’s usually the right choice.

Google Play sets a minimum target SDK for new apps and updates, and raises it every year. If Google Play rejects your upload because the target SDK is too low, raise the engine and the target SDK together. Google’s current requirement is on Target API level requirements.

Google Play also requires apps targeting Android 15 or later to support 16 KB memory pages. If you get a 16 KB page size warning, use the newest engine, then update any plugin that includes native libraries. The warning usually names the library.

Check your edit-config entries

edit-config changes AndroidManifest.xml or the iOS Info.plist during the build. When an edit-config is wrong, the build can fail, or worse, succeed while leaving out what you needed. Check these:

  • Put it inside the right <platform name="..."> tag.
  • Use the exact key Apple or Google expects. For example, if your app asks for “always” location access, iOS needs NSLocationAlwaysAndWhenInUseUsageDescription as well as NSLocationWhenInUseUsageDescription. If an error names a missing key, copy the name exactly.
  • For Info.plist, use file="*-Info.plist". For Android, use file="AndroidManifest.xml" with a target XPath such as /manifest/application.
  • If you get Unable to graft xml at selector, the target doesn’t exist in the file. Check the path.
<platform name="ios">
  <edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
    <string>This app uses the camera to scan documents.</string>
  </edit-config>
</platform>

To check what ended up in the built app, unzip the .ipa and look at Info.plist, or open the .apk in Android Studio’s APK Analyzer.

A new cordova-ios release broke my iOS build

New major versions of cordova-ios regularly break older plugins. If an iOS build that used to work starts failing on cordova platform add or while compiling a plugin, pin the previous cordova-ios version and rebuild:

<engine name="ios" spec="7.1.1" />

The pre-installed cordova-ios versions are on Build environment. Then check whether the plugin named in the error has a newer release.

Common error messages and what they mean

index.html not found.

VoltBuilder couldn’t find www/index.html. Zip the contents of your project folder, so that config.xml and www are at the top of the zip. The folder must be called www in lower case. See How to set up your project.

Badly formed VoltBuilder.json

voltbuilder.json isn’t valid JSON. Look for a trailing comma after the last item, a missing comma, or curly “smart” quotes added by a word processor. Paste it into a JSON validator to find the line.

Plugin '...' has invalid spec: '...'. Plugin specs should be in the form '1.2.3'.

The plugin’s spec is a URL or path. On the Free, Indy and Pro plans, plugins must come from npm with a version number. See Pin your plugin versions.

Plugin '...' is not listed in https://npmjs.com.

Check the spelling of the plugin name against npm. Plugins that aren’t published on npm need an Enterprise plan.

Plugin '...' is not included in Free Plan.

The Free plan includes the core plugins only. Other plugins need a paid plan.

Project is larger than allowed for the ... Plan

Your zip is over your plan’s size limit. Leave out node_modules, platforms and plugins folders (VoltBuilder installs these itself), and keep icon and splash source files outside www.

failed to read PNG signature: file does not start with PNG signature

An icon or splash file has a .png name but isn’t a PNG, usually a JPEG that was renamed. Re-export it as a real PNG.

Keystore was tampered with, or password was incorrect

androidKeystorePassword doesn’t match your keystore. See Incorrect androidAlias or androidAliasPassword to check the details.

voltbuilder.json does not have "iosDevP12Password" or iOS Development .p12 not found

iOS debug builds need a development certificate and provisioning profile too. This is Apple’s requirement. See Signing and store upload problems.

iosPackageType must be ad-hoc, app-store, or enterprise.

iOS release builds need iosPackageType in voltbuilder.json. See Signing and store upload problems.

UserError: ERROR: Cannot obtain the content provider public id (iOS)

App Store Connect returns this when the Apple ID in appStoreConnectAccount belongs to more than one App Store Connect team, so Apple can’t tell which team the upload is for.

The simplest fix is to upload with an Apple ID that belongs only to the team that owns the app. In App Store Connect, go to Users and Access, add a user for that team (the App Manager role is enough to upload), then create an app-specific password for that user and put both in voltbuilder.json.

Remote Debugging

If your app fails at runtime, the next step is to open a remote debugging session to debug your app. You’ll be able to see if there are error messages on the Console.

For Android, use Chrome Remote Debugging.

For iOS, use Safari Remote Debugging (MacOS only) or Inspect.dev (Windows or MacOS).

If you want to look at the console at runtime without connecting a remote browser, use the cordova-console.log library. It hijacks the output of console.log() sending it into a div in your app. You can then view it on your device.

Another ($) option is BrowserStack

Obsolete use of config-file in config.xml.

Up to cli-7.0.1, PhoneGap allowed this type of clause:

<config-file platform="ios" parent="SomeXMLElement" mode="replace">
  <SomeXMLElement someAttribute="text" >Go Skiing</SomeXMLElement>
</config-file>

Apache Cordova started using the same <config-file command for its plugins, which conflicted with the PhoneGap implementation. PhoneGap then changed to use Cordova’s edit-config. You’ll need to change these in your config.xml. Consult the documentation for the affected controls to get the details.

Example 1: Change this:

<config-file parent="UIStatusBarHidden" platform="ios" target="*-Info.plist">
    <true/>
</config-file>

to this:

<edit-config file="*-Info.plist" mode="merge" target="UIStatusBarHidden">
    <true/>
</edit-config>

Example 2: Change this:

<config-file platform="android" parent="/manifest" mode="merge">
  <supports-screens android:anyDensity="true" android:resizeable="true"
    android:smallScreens="true" android:normalScreens="true" android:largeScreens="true"
    android:xlargeScreens="true" />
</config-file>

to this:

<edit-config file="AndroidManifest.xml" target="/manifest/supports-screens" mode="merge">
  <supports-screens android:anyDensity="true" android:resizeable="true"
    android:smallScreens="true" android:normalScreens="true" android:largeScreens="true"
    android:xlargeScreens="true" />
</edit-config>

Example 3: Change this:

<gap:config-file overwrite="true" parent="NSLocationAlwaysUsageDescription" platform="ios">
    <string>This app needs access to your location to determine your pickup point</string>
</gap:config-file>

to this:

<edit-config target="NSLocationAlwaysUsageDescription" file="*-Info.plist" mode="merge">
    <string>This app needs access to your location to determine your pickup point</string>
</edit-config>

Example 4: Change this:

<gap:config-file overwrite="true" parent="NSLocationWhenInUseUsageDescription" platform="ios">
    <string>This app needs access to your location to determine your pickup point</string>
</gap:config-file>

to this:

<edit-config target="NSLocationWhenInUseUsageDescription" file="*-Info.plist" mode="overwrite">
    <string>Allow the app to know your location</string>
</edit-config>

Example 5: Change this:

<config-file platform="winphone" parent="/Deployment" mode="replace">
  <DefaultLanguage xmlns="" code="da-DK"/>
  <Languages xmlns="">
    <Language code="da-DK"/>
    <Language code="en-US"/>
  </Languages>
</config-file>

to nothing. “winphone” is no longer supported.

UIWebView

iOS has dropped support for UIWebView. If your config.xml file includes the UIWebView plugin, you’ll get an error. Remove it, and replace with this:

<platform name="ios">
    <preference name="WKWebViewOnly" value="true" />

    <feature name="CDVWKWebViewEngine">
        <param name="ios-package" value="CDVWKWebViewEngine" />
    </feature>

    <preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" />
</platform>

There is more information in the Apache Cordova docs. You may not actually have UIWebView in your config.xml file - but it could be used by other plugins. In that case, you’ll need to update the other plugins.

Permissions

If you are using the location, camera or photo album, iOS requires you to ask the user for permission first. You can change the wording: for example, to use a different language. Declare these in your config.xml file as follows:

<platform name="ios">
  <edit-config target="NSLocationAlwaysUsageDescription" file="*-Info.plist" mode="overwrite">
    <string>Allow the app to know your location</string>
  </edit-config>
  <edit-config target="NSLocationWhenInUseUsageDescription" file="*-Info.plist" mode="overwrite">
    <string>Allow the app to know your location</string>
  </edit-config>
  <edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="overwrite">
    <string>App would like to access Camera to take picture of any document that you want to upload as attachment to your message</string>
  </edit-config>
  <edit-config target="NSPhotoLibraryUsageDescription" file="*-Info.plist" mode="overwrite">
    <string>Allow the app to open Photo Library to take picture of any document that you want to upload as attachment to your message</string>
  </edit-config>
</platform>

CORS error and white screen on startup

If your app has a white screen on startup, you probably have an error in your code which stops it from running. To see the error, use Remote Debugging.

The most common reason is Content Security Policy (CSP) errors. Both Android and iOS require apps only access URLs which are known and secure. The CSP sets those rules. Here’s a very simple CSP - put this in your index.html file:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' ">

(You’ll want to make this more restrictive, so that only the files you actually need are authorized)

Error messages you might see include Cross origin requests are only supported for HTTP and XMLHttpRequest cannot load ... due to access control checks.

You may also need to add lines to your config.xml file:

    <!-- To allow connections to other resources, you must explicitly permit them using `access` tags. -->
    <!-- https://s.apache.org/cdv-network-request-access -->
    <!-- Example:
    <access allow="https://cordova.apache.org" />
    -->

    <!-- To control which URLs the WebView itself can be navigated to, use the `allow-navigation` tags. -->
    <!-- https://s.apache.org/cdv-allow-navigation -->
    <!-- Example:
    <allow-navigation href="https://cordova.apache.org/*" />
    -->

    <!-- To control which URLs the app is allowed to ask the system to open, use the `allow-intent` tags. -->
    <!-- https://s.apache.org/cdv-allow-intent -->
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />

AndroidX

If your project uses AndroidX dependencies, AndroidX needs to be enabled. Add this to your config.xml:

<preference name="AndroidXEnabled" value="true" />

AndroidX is the replacement for the Android Support Library, which is no longer maintained. Many plugins used ASL - hopefully the plugins you use have been updated to use AndroidX.

You may also see a message like this: error: package android.support.v4.content does not exist. If you get this, you are using a plugin which has not been updated. Check npmjs.com for updates. You can also add this plugin, which allows older plugins to be used in AndroidX projects:

<plugin name="cordova-plugin-androidx-adapter" />

HTTP Requests not working

Both Android and iOS have started enforcing TLS and CORS/CSP.

From Android 9 Pie onwards, requests without encryption will not work, and by default, Android expects you to use TLS.

The easy way to bypass this is to add this plugin to your config.xml

<plugin name="cordova-plugin-cleartext" />

Although you should try to make your requests through the secure https protocol.

Incorrect androidAlias or androidAliasPassword

When your Android certificate is created, it will have an Alias and a Password for that alias. You need to put that information in your voltbuilder.json file for your app to be signed.

If you used VoltSigner to create your certificate, androidAlias is always set to key0. androidAliasPassword is set to the same password as the certificate.

If you do not have the information about your alias, you can use the following command to get the information from your .p12 file: openssl pkcs12 -info -in yourcert.p12

The openssl command is available on MacOS, and can be downloaded for Windows here.

There are certain lines in the output you want to identify:

Bag Attributes
    friendlyName: key0
    localKeyID: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

The friendlyName is the androidAlias. You’ll need to type in two passwords. The second “PEM pass phrase” is your androidAliasPassword.

Apps not appearing on routing list

(Applicable to Android 11+)

If your app calls other apps at runtime, using a plugin like cordova-plugin-app-launcher, you need to declare the other apps in your config.xml. You can do so by adding this code:

    <config-file target="AndroidManifest.xml" parent="/manifest">
      <queries>
          <package android:name="com.voltbuilder.test" />
          <package android:name="com.whatsapp" />
      </queries>
    </config-file>

More information here.

Cordova not found (runtime)

If your project builds properly, but does not work properly at runtime, use Remote Debugging to see if any errors are thrown.

If you see Cordova not found on the Console, there are a couple of possibilities:

  • Your index.html file does not have this statement:
<script src="cordova.js"></script>
  • There is a problem with a plugin. No error was detected in the build, so VoltBuilder thinks the build was successful. To isolate which plugin is the cause, look through the log for warnings or other messages. You should also check to make sure all your plugins are up to date.

What to send if you need help

If none of this solves it, ask on the forum or email support. Include:

  • The build ID. After a build, click Copy Build Id on the upload page. With it, we can open your log directly.
  • The error line from the log, copied as text rather than a screenshot.
  • Your config.xml and voltbuilder.json, with passwords removed.
  • What changed since the last build that worked, if there was one.
Join Our Newsletter
Stay up to date on all of the latest news and updates for VoltBuilder