apache/cordova-android · error · CordovaError

Failed to install apk to target: ${output}

Error message

Failed to install apk to target: ${output}

What it means

Thrown by Adb.install(target, packagePath) after running `adb -s <target> install <apk>`. adb exits with code 0 even when installation fails and only prints a `Failure [INSTALL_...]` line to stdout, so the library regex-matches /Failure/ on stdout and throws the raw adb output. Two known codes get an appended hint: INSTALL_PARSE_FAILED_NO_CERTIFICATES (unsigned APK, hints at --keystore/--buildConfig) and INSTALL_FAILED_VERSION_DOWNGRADE (hints at uninstall or bump versionCode). Every other adb failure code appears verbatim without a hint.

Source

Thrown at lib/Adb.js:70

    const args = ['-s', target, 'install'];
    if (replace) args.push('-r');

    const opts = { cwd: os.tmpdir(), ...execOptions };

    return execa('adb', args.concat(packagePath), opts).then(({ stdout: output }) => {
        // adb does not return an error code even if installation fails. Instead it puts a specific
        // message to stdout, so we have to use RegExp matching to detect installation failure.
        if (output.match(/Failure/)) {
            if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
                output += '\n\n' + 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
                    ' or sign and deploy the unsigned apk manually using Android tools.';
            } else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
                output += '\n\n' + 'You\'re trying to install apk with a lower versionCode that is already installed.' +
                    '\nEither uninstall an app or increment the versionCode.';
            }

            throw new CordovaError('Failed to install apk to target: ' + output);
        }
    });
};

Adb.uninstall = function (target, packageId) {
    events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
    return execa('adb', ['-s', target, 'uninstall', packageId], { cwd: os.tmpdir() }).then(({ stdout }) => stdout);
};

Adb.shell = function (target, shellCommand) {
    events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
    const args = ['-s', target, 'shell'];
    shellCommand = shellCommand.split(/\s+/);
    return execa('adb', args.concat(shellCommand), { cwd: os.tmpdir() })
        .then(({ stdout }) => stdout)
        .catch(error => Promise.reject(new CordovaError(`Failed to execute shell command "${shellCommand}" on device: ${error}`)));
};

View on GitHub (pinned to 7c1e190064)

Solutions

  1. Read the Failure [INSTALL_...] code inside the message - it names the exact adb failure; NO_CERTIFICATES and VERSION_DOWNGRADE already carry a hint line.
  2. For INSTALL_FAILED_VERSION_DOWNGRADE: bump android-versionCode in config.xml (or remove it so it auto-increments), or run `adb -s <target> uninstall <package-id>` first.
  3. For INSTALL_PARSE_FAILED_NO_CERTIFICATES: sign the build via `-- --keystore=... --alias=...` or `--buildConfig=build.json`, or sign the unsigned APK with apksigner and install manually.
  4. For INSTALL_FAILED_UPDATE_INCOMPATIBLE: uninstall the existing app (`adb -s <target> uninstall <package-id>`) so the new signature can replace it.
  5. For INSUFFICIENT_STORAGE / ABI problems: free device space or build for the device ABI (check with `adb shell getprop ro.product.cpu.abi`).

Example fix

// before (config.xml - device already has 10002 installed)
<widget ... android-versionCode="10001">

// after
<widget ... android-versionCode="10003">
Defensive patterns

Strategy: try-catch

Validate before calling

// Before deploying: catch VERSION_DOWNGRADE / signature mismatch up front
const installed = await Adb.shell(target, `dumpsys package ${packageId} | grep versionCode`).catch(() => null);
// null -> app not installed; otherwise compare the reported versionCode against your APK's before Adb.install

Try / catch

try {
  await Adb.install(target, apkPath);
} catch (e) {
  if (e instanceof CordovaError && /Failed to install apk/.test(e.message)) {
    const code = /\[([A-Z_]+)\]/.exec(e.message)?.[1];
    if (code === 'INSTALL_FAILED_VERSION_DOWNGRADE' || code === 'INSTALL_FAILED_UPDATE_INCOMPATIBLE') {
      await Adb.uninstall(target, packageId);
      return Adb.install(target, apkPath); // single retry after uninstall
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling Adb.install (directly, or via `cordova run android` / `cordova emulate android` during the deploy step) when adb stdout contains 'Failure', e.g. 'Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]', 'Failure [INSTALL_FAILED_VERSION_DOWNGRADE]', 'Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE]', 'Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE]'.

Common situations: Deploying a release APK that was never signed; switching branches or resetting CI so the built versionCode is lower than the one already on the device; installing over an app signed with a different keystore; full device storage; APK ABI not matching the device/emulator.

Related errors


AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22). Data as JSON: /api/errors/28ba6d4757830213. Report an issue: GitHub.