elastic/elasticsearch · error · IllegalStateException

Forbidden APIs cli failed: {forbiddenApisOutput}

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.

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)

Solutions

  1. Read the full forbiddenApisOutput text in the exception/Gradle log to see which classes/APIs were flagged.
  2. For legitimate violations, fix the calling code or add a justified class-level exclusion in thirdPartyAudit { ... }.
  3. If forbiddenapis itself errored (e.g. signature mismatch), update or align the signature file / bundled JDK version.
  4. 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

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

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/7f379179ce382cfe. Report an issue: GitHub.