{"id":"19a467ef91a3c8da","repo":"apache/kafka","slug":"found-d-internal-api-usage-violations-see-report-19a467","errorCode":null,"errorMessage":"Found %d internal API usage violations. See report: %s","messagePattern":"Found (.+?) internal API usage violations\\. See report: (.+?)","errorType":"exception","errorClass":"MojoFailureException","httpStatus":null,"severity":"error","filePath":"api-checker/maven-plugin/src/main/java/org/apache/kafka/maven/KafkaInternalApiCheckerMojo.java","lineNumber":172,"sourceCode":"        reporter.writeTextReport(violations, suppressions, reportFile);\n        reporter.printToConsole(violations, suppressions);\n\n        getLog().info(\"Internal API usage check completed. Report written to: \" + reportFile.getAbsolutePath());\n\n        long unjustified = suppressions.stream().filter(PublicApiViolation::lacksReason).count();\n        if (unjustified > 0) {\n            getLog().warn(unjustified + \" suppression(s) carry no reason — KIP-1265 requires a justification on every @SuppressKafkaInternalApiUsage\");\n        }\n\n        if (violations.isEmpty()) {\n            getLog().info(\"No internal API usage found.\");\n            return;\n        }\n\n        String message = String.format(\"Found %d internal API usage violations. See report: %s\",\n                violations.size(), reportFile.getAbsolutePath());\n        if (failOnViolation) {\n            throw new MojoFailureException(message);\n        }\n        getLog().warn(message);\n    }\n\n    /**\n     * Default to the project's main compiled output, matching the Gradle plugin's behaviour\n     * (which feeds {@code sourceSets.main.output.classesDirs}). Test code legitimately uses\n     * internal/test utilities, so including it by default would create noise that isn't a\n     * real consumer-side concern. Users who want to scan test code can opt in by setting\n     * {@code <classesDirectories>} explicitly.\n     */\n    private List<File> getDefaultClassesDirectories() {\n        List<File> dirs = new ArrayList<>();\n        File mainClasses = new File(project.getBuild().getOutputDirectory());\n        if (mainClasses.exists()) {\n            dirs.add(mainClasses);\n        }\n        return dirs;","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/api-checker/maven-plugin/src/main/java/org/apache/kafka/maven/KafkaInternalApiCheckerMojo.java#L154-L190","documentation":"Thrown by the kafka-internal-api-checker Maven plugin (MojoFailureException) when bytecode scanning of the project's compiled classes finds references to Kafka internal (non-public) APIs and the <failOnViolation> flag is true. It enforces KIP-1265 / the @SuppressKafkaInternalApiUsage discipline so consumers of kafka-clients do not silently bind to unstable internals. The message reports the violation count and points to the text report written to <reportFile>.","triggerScenarios":"Binding the kafka-internal-api-checker:maven-plugin goal to the build and having compiled classes that reference org.apache.kafka.* packages outside the public API include list. Triggered during the verify/package phase once classes are compiled. Only fails when failOnViolation=true (the message degrades to a warn otherwise).","commonSituations":"Upgrading the kafka-clients dependency to a version whose internal classes were refactored/removed, after a transitive dependency starts reaching into internals, or when a previously-public class was reclassified as internal. CI builds that newly enable the plugin will surface long-standing violations for the first time.","solutions":["Open the report at the path printed in the message and read each PublicApiViolation entry to see which internal symbol is referenced and from which class.","Refactor the offending call site to use the supported public API equivalent (e.g. AdminClient / KafkaClient APIs listed in build.gradle javadoc includes).","If the usage is intentional and justified, annotate with @SuppressKafkaInternalApiUsage(reason=...) per KIP-1265 so it is recorded as a suppression rather than a violation.","Temporarily set <failOnViolation>false</failOnViolation> in the plugin configuration to unblock CI while the fix is prepared (not recommended as a permanent state)."],"exampleFix":"// before\norg.apache.kafka.common.protocol.ApiKeys apikey = org.apache.kafka.common.protocol.ApiKeys.METADATA;\n// after (use public API or suppress)\n@SuppressKafkaInternalApiUsage(reason = \"Need APIKeys ordinal for wire compat shim, tracked in KAFKA-12345\")\norg.apache.kafka.common.protocol.ApiKeys apikey = org.apache.kafka.common.protocol.ApiKeys.METADATA;","handlingStrategy":"validation","validationCode":"// This is a Maven-plugin build failure (MojoFailureException), not a runtime\n// exception. Gate the build *before* enabling failOnViolation:\n//   1. Configure <failOnViolation>false</failOnViolation> in pom.xml.\n//   2. Read the report at ${project.build.directory}/reports/kafka-internal-api-usage.txt.\n//   3. For each VIOLATION line, replace the internal-API call with a public API\n//      equivalent, or annotate the call site:\n//          @SuppressKafkaInternalApiUsage(reason=\"<why public API cannot be used>\")\n//   4. Re-enable <failOnViolation>true</failOnViolation> only when violations == 0.\n//\n// CI gate (Groovy/shell) before promoting the build:\n//   report=\"${project.build.directory}/reports/kafka-internal-api-usage.txt\"\n//   n=$(grep -c '^VIOLATION' \"$report\" || true)\n//   [ \"$n\" -eq 0 ] || { echo \"Fix $n internal-API violations first\"; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Program only against the public packages (org.apache.kafka.clients.producer|consumer|admin and org.apache.kafka.common.serialization|config|errors); treat anything under *.internal.* or *.internals.* as off-limits.","Run the kafka-internal-api-checker Mojo in CI on every pull request and gate merge on zero unjustified violations.","When a suppression is genuinely unavoidable, always give @SuppressKafkaInternalApiUsage a concrete reason — KIP-1265 flags a missing reason as a warning in its own right.","Pin the Kafka client version; internal APIs can shift between minor releases, so a silent dependency bump can newly flag previously-clean code."],"tags":["build","maven","api-compat","kip-1265"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}