{"record":{"id":"7f379179ce382cfe","repo":"elastic/elasticsearch","slug":"forbidden-apis-cli-failed-forbiddenapisoutput","errorCode":null,"errorMessage":"Forbidden APIs cli failed: {forbiddenApisOutput}","messagePattern":"Forbidden APIs cli failed: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ThirdPartyAuditTask.java","lineNumber":424,"sourceCode":"            }\n            spec.jvmArgs(\"-Xmx1g\");\n            spec.getMainClass().set(\"de.thetaphi.forbiddenapis.cli.CliMain\");\n            spec.args(\"-f\", getSignatureFile().getAbsolutePath(), \"-d\", getJarExpandDir(), \"--debug\", \"--allowmissingclasses\");\n            spec.setErrorOutput(errorOut);\n            if (getLogger().isInfoEnabled() == false) {\n                spec.setStandardOutput(new NullOutputStream());\n            }\n            spec.setIgnoreExitValue(true);\n        });\n        if (OS.current().equals(OS.LINUX) && result.getExitValue() == SIG_KILL_EXIT_VALUE) {\n            throw new IllegalStateException(\"Third party audit was killed buy SIGKILL, could be a victim of the Linux OOM killer\");\n        }\n        final String forbiddenApisOutput;\n        try (ByteArrayOutputStream outputStream = errorOut) {\n            forbiddenApisOutput = outputStream.toString(StandardCharsets.UTF_8);\n        }\n        if (EXPECTED_EXIT_CODES.contains(result.getExitValue()) == false) {\n            throw new IllegalStateException(\"Forbidden APIs cli failed: \" + forbiddenApisOutput);\n        }\n        return forbiddenApisOutput;\n    }\n\n    /** Returns true iff the build Java version is the same as the given version. */\n    private boolean isJavaVersion(JavaVersion version) {\n        if (getRuntimeJavaVersion().isPresent()) {\n            return getRuntimeJavaVersion().get().equals(version);\n        }\n        return version.getMajorVersion().equals(VersionProperties.getBundledJdkMajorVersion());\n    }\n\n    private Set<String> runJdkJarHellCheck() throws IOException {\n        ByteArrayOutputStream standardOut = new ByteArrayOutputStream();\n        ExecResult execResult = execOperations.javaexec(spec -> {\n            spec.classpath(getJdkJarHellClasspath(), getThirdPartyClasspath());\n            spec.getMainClass().set(JDK_JAR_HELL_MAIN_CLASS);\n            spec.args(getJarExpandDir());","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ThirdPartyAuditTask.java#L406-L442","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: code calls a forbidden API\nRuntime.getRuntime().exit(0);\n// after: use an allowed alternative\nSystem.exit(0); // if permitted by signatures, otherwise remove the call","handlingStrategy":"try-catch","validationCode":"// Pre-check: scan sources for known forbidden patterns is not feasible generically;\n// instead keep forbiddenapis signatures updated and run the audit frequently in CI.","typeGuard":null,"tryCatchPattern":"try { String out = runForbiddenAPIsCli(); }\ncatch (IllegalStateException e) {\n    // e.getMessage() contains the full forbiddenapis output — fix code or add justified exclusion\n    throw e;\n}","preventionTips":["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."],"tags":["build","gradle","precommit","forbiddenapis"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}