elastic/elasticsearch · error · IllegalStateException
Forbidden APIs cli failed
Error message
Forbidden APIs cli failed: {forbiddenApisOutput} What it means
Thrown by ThirdPartyAuditTask.runForbiddenAPIsCli when the forbiddenapis CLI exits with a code not in EXPECTED_EXIT_CODES. The captured stderr (forbiddenApisOutput) is attached so the developer can see the actual forbiddenapis error output. This is the generic 'forbiddenapis reported violations or crashed' failure path.
Solutions
- Read the full forbiddenApisOutput text in the exception/Gradle log to see which classes/APIs were flagged.
- For legitimate violations, fix the calling code or add a justified class-level exclusion in thirdPartyAudit { ... }.
- If forbiddenapis itself errored (e.g. signature mismatch), update or align the signature file / bundled JDK version.
- Re-run :<project>:thirdPartyAudit after the fix to confirm a clean (expected) exit code.
Example fix
// before: code calls a forbidden API Runtime.getRuntime().exit(0); // after: use an allowed alternative System.exit(0); // if permitted by signatures, otherwise remove the call
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check: scan sources for known forbidden patterns is not feasible generically; // instead keep forbiddenapis signatures updated and run the audit frequently in CI.
Try / catch
try { String out = runForbiddenAPIsCli(); }
catch (IllegalStateException e) {
// e.getMessage() contains the full forbiddenapis output — fix code or add justified exclusion
throw e;
} Prevention
- Run thirdPartyAudit in CI on every PR so violations surface at review time.
- Keep the signature file aligned with the bundled JDK version.
- When adding a dependency, run the audit locally to catch newly-introduced forbidden calls.
When it happens
Trigger: After running forbiddenapis with setIgnoreExitValue(true), the exit code is checked against EXPECTED_EXIT_CODES. A non-matching code means forbiddenapis either found forbidden API usages (its normal non-zero exit) or hit an internal error; the captured stderr is surfaced in the exception message.
Common situations: Code uses an API forbidden by the configured signature file (the intended failure mode); signature file references a class/method that no longer exists causing forbiddenapis to error; misconfigured -d jar expand dir; JDK version mismatch between the build and the forbiddenapis signatures; a new dependency introduces forbidden calls.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Third party audit task is not configured correctly
- Failed to load keywords JSON from
- Failed to write keywords report
- Third party audit was killed buy SIGKILL, could be a victim…
- Unnecessary split package ignores found
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/7f379179ce382cfe.
Report an issue: GitHub.
Appendix: source
Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ThirdPartyAuditTask.java:424
}
spec.jvmArgs("-Xmx1g");
spec.getMainClass().set("de.thetaphi.forbiddenapis.cli.CliMain");
spec.args("-f", getSignatureFile().getAbsolutePath(), "-d", getJarExpandDir(), "--debug", "--allowmissingclasses");
spec.setErrorOutput(errorOut);
if (getLogger().isInfoEnabled() == false) {
spec.setStandardOutput(new NullOutputStream());
}
spec.setIgnoreExitValue(true);
});
if (OS.current().equals(OS.LINUX) && result.getExitValue() == SIG_KILL_EXIT_VALUE) {
throw new IllegalStateException("Third party audit was killed buy SIGKILL, could be a victim of the Linux OOM killer");
}
final String forbiddenApisOutput;
try (ByteArrayOutputStream outputStream = errorOut) {
forbiddenApisOutput = outputStream.toString(StandardCharsets.UTF_8);
}
if (EXPECTED_EXIT_CODES.contains(result.getExitValue()) == false) {
throw new IllegalStateException("Forbidden APIs cli failed: " + forbiddenApisOutput);
}
return forbiddenApisOutput;
}
/** Returns true iff the build Java version is the same as the given version. */
private boolean isJavaVersion(JavaVersion version) {
if (getRuntimeJavaVersion().isPresent()) {
return getRuntimeJavaVersion().get().equals(version);
}
return version.getMajorVersion().equals(VersionProperties.getBundledJdkMajorVersion());
}
private Set<String> runJdkJarHellCheck() throws IOException {
ByteArrayOutputStream standardOut = new ByteArrayOutputStream();
ExecResult execResult = execOperations.javaexec(spec -> {
spec.classpath(getJdkJarHellClasspath(), getThirdPartyClasspath());
spec.getMainClass().set(JDK_JAR_HELL_MAIN_CLASS);
spec.args(getJarExpandDir());View on GitHub (pinned to db6a809a66)