{"record":{"id":"28ba6d4757830213","repo":"apache/cordova-android","slug":"failed-to-install-apk-to-target-output","errorCode":null,"errorMessage":"Failed to install apk to target: ${output}","messagePattern":"Failed to install apk to target: (.+?)","errorType":"exception","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/Adb.js","lineNumber":70,"sourceCode":"\n    const args = ['-s', target, 'install'];\n    if (replace) args.push('-r');\n\n    const opts = { cwd: os.tmpdir(), ...execOptions };\n\n    return execa('adb', args.concat(packagePath), opts).then(({ stdout: output }) => {\n        // adb does not return an error code even if installation fails. Instead it puts a specific\n        // message to stdout, so we have to use RegExp matching to detect installation failure.\n        if (output.match(/Failure/)) {\n            if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {\n                output += '\\n\\n' + 'Sign the build using \\'-- --keystore\\' or \\'--buildConfig\\'' +\n                    ' or sign and deploy the unsigned apk manually using Android tools.';\n            } else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {\n                output += '\\n\\n' + 'You\\'re trying to install apk with a lower versionCode that is already installed.' +\n                    '\\nEither uninstall an app or increment the versionCode.';\n            }\n\n            throw new CordovaError('Failed to install apk to target: ' + output);\n        }\n    });\n};\n\nAdb.uninstall = function (target, packageId) {\n    events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');\n    return execa('adb', ['-s', target, 'uninstall', packageId], { cwd: os.tmpdir() }).then(({ stdout }) => stdout);\n};\n\nAdb.shell = function (target, shellCommand) {\n    events.emit('verbose', 'Running adb shell command \"' + shellCommand + '\" on target ' + target + '...');\n    const args = ['-s', target, 'shell'];\n    shellCommand = shellCommand.split(/\\s+/);\n    return execa('adb', args.concat(shellCommand), { cwd: os.tmpdir() })\n        .then(({ stdout }) => stdout)\n        .catch(error => Promise.reject(new CordovaError(`Failed to execute shell command \"${shellCommand}\" on device: ${error}`)));\n};\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/Adb.js#L52-L88","documentation":"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.","triggerScenarios":"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]'.","commonSituations":"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.","solutions":["Read the Failure [INSTALL_...] code inside the message - it names the exact adb failure; NO_CERTIFICATES and VERSION_DOWNGRADE already carry a hint line.","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.","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.","For INSTALL_FAILED_UPDATE_INCOMPATIBLE: uninstall the existing app (`adb -s <target> uninstall <package-id>`) so the new signature can replace it.","For INSUFFICIENT_STORAGE / ABI problems: free device space or build for the device ABI (check with `adb shell getprop ro.product.cpu.abi`)."],"exampleFix":"// before (config.xml - device already has 10002 installed)\n<widget ... android-versionCode=\"10001\">\n\n// after\n<widget ... android-versionCode=\"10003\">","handlingStrategy":"try-catch","validationCode":"// Before deploying: catch VERSION_DOWNGRADE / signature mismatch up front\nconst installed = await Adb.shell(target, `dumpsys package ${packageId} | grep versionCode`).catch(() => null);\n// null -> app not installed; otherwise compare the reported versionCode against your APK's before Adb.install","typeGuard":null,"tryCatchPattern":"try {\n  await Adb.install(target, apkPath);\n} catch (e) {\n  if (e instanceof CordovaError && /Failed to install apk/.test(e.message)) {\n    const code = /\\[([A-Z_]+)\\]/.exec(e.message)?.[1];\n    if (code === 'INSTALL_FAILED_VERSION_DOWNGRADE' || code === 'INSTALL_FAILED_UPDATE_INCOMPATIBLE') {\n      await Adb.uninstall(target, packageId);\n      return Adb.install(target, apkPath); // single retry after uninstall\n    }\n  }\n  throw e;\n}","preventionTips":["Bump android-versionCode (or let Cordova auto-increment it) on every build you deploy.","Keep one keystore per package id; switching debug/release keystores requires uninstalling first.","Keep free storage on test devices; check `adb shell df /data` when installs start failing.","Match the APK ABI to the device (`adb shell getprop ro.product.cpu.abi`) before installing."],"tags":["adb","apk-install","cordova-run","android","signing","versioncode"],"backgroundTag":"apk-install-failed","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}