apache/cordova-android · error · CordovaError
Failed to find 'JAVA_HOME' environment variable. Try setting
Error message
Failed to find 'JAVA_HOME' environment variable. Try setting it manually.
What it means
Branch of java env detection: JAVA_HOME unset, javac found on PATH, and on macOS the helper /usr/libexec/java_home exists. The code execs it to discover JAVA_HOME; if that command exits non-zero (no JVM registered with macOS) it throws the generic 'Failed to find JAVA_HOME' message.
Source
Thrown at lib/env/java.js:97
const javaHome = environment.CORDOVA_JAVA_HOME || environment.JAVA_HOME;
if (javaHome) {
// Ensure that CORDOVA_JAVA_HOME overrides
environment.JAVA_HOME = javaHome;
// Ensure that the JAVA_HOME bin path is before anything else
// to cover cases where different Java versions is in the PATH
environment.PATH = path.join(environment.JAVA_HOME, 'bin') + path.delimiter + environment.PATH;
} else {
const javacPath = utils.forgivingWhichSync('javac');
if (javacPath) {
// OS X has a command for finding JAVA_HOME.
const find_java = '/usr/libexec/java_home';
const default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting it manually.';
if (fs.existsSync(find_java)) {
try {
environment.JAVA_HOME = (await execa(find_java)).stdout;
} catch (ex) {
events.emit('verbose', ex.shortMessage);
throw new CordovaError(default_java_error_msg);
}
} else {
// See if we can derive it from javac's location.
const maybeJavaHome = path.dirname(path.dirname(javacPath));
if (fs.existsSync(path.join(maybeJavaHome, 'bin', 'java')) ||
fs.existsSync(path.join(maybeJavaHome, 'bin', 'java.exe'))) {
environment.JAVA_HOME = maybeJavaHome;
} else {
throw new CordovaError(default_java_error_msg);
}
}
} else if (utils.isWindows()) {
const baseDirs = [environment.ProgramFiles, environment['ProgramFiles(x86)']];
const globOpts = { absolute: true, onlyDirectories: true };
const flatMap = (arr, f) => [].concat(...arr.map(f));
const jdkDir = flatMap(baseDirs, cwd => {
return glob.sync('java/jdk*', { cwd, ...globOpts });
}View on GitHub (pinned to 7c1e190064)
Solutions
- Install a proper JDK on macOS (e.g. `brew install --cask temurin@8` or the Oracle installer) so /usr/libexec/java_home can find it.
- Or bypass detection: export JAVA_HOME manually to the JDK root.
- Diagnose registrations with `/usr/libexec/java_home -V`.
Example fix
# before $ /usr/libexec/java_home Unable to find any JVM in this Home. # after $ brew install --cask temurin@8 $ /usr/libexec/java_home # prints the JDK root
Defensive patterns
Strategy: validation
Validate before calling
if (!process.env.JAVA_HOME && process.platform === 'darwin' && fs.existsSync('/usr/libexec/java_home')) {
const probe = await execa('/usr/libexec/java_home').catch(() => null);
if (!probe || !probe.stdout) {
throw new Error('No JVM registered with macOS - install a JDK (brew install --cask temurin@8) or export JAVA_HOME');
}
} Try / catch
try {
await check_reqs.check_java();
} catch (e) {
if (/Failed to find 'JAVA_HOME'/.test(e.message) && process.platform === 'darwin') {
// run `/usr/libexec/java_home -V` and either register a JDK or export JAVA_HOME manually
}
throw e;
} Prevention
- Install JDKs via proper installers/casks so macOS registers them with /usr/libexec/java_home.
- Never delete a JDK directory by hand; uninstall it so registrations stay consistent.
- Set JAVA_HOME explicitly in CI instead of relying on macOS inference.
When it happens
Trigger: `cordova requirements android` / build on macOS where javac is reachable (shim, manual install) but /usr/libexec/java_home reports 'Unable to find any JVM in this Home' - i.e. no JDK registered via the standard macOS mechanism.
Common situations: JDK removed by deleting files instead of uninstalling; a JDK unpacked manually to /opt without being registered; Homebrew-installed javac without the Cask JDK; macOS updates clearing old JVM registrations.
Related errors
- Failed to run "javac -version", make sure that you have a JD
- Failed to find 'ANDROID_HOME' environment variable. Try sett
- Failed to find 'ANDROID_HOME' environment variable. Try sett
- Failed to find 'ANDROID_HOME' environment variable. Try sett
- 'ANDROID_HOME' environment variable is set to non-existent p
AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22).
Data as JSON: /api/errors/80ceb53c9a35fc9a.
Report an issue: GitHub.