{"id":"59248298df5f7264","repo":"apache/kafka","slug":"no-project-jars-configured-on-kafkapublicapichecke","errorCode":null,"errorMessage":"No project JARs configured on kafkaPublicApiChecker.projectJarFiles — the checker needs at least one classes/jar source to build the API surface.","messagePattern":"No project JARs configured on kafkaPublicApiChecker\\.projectJarFiles — the checker needs at least one classes/jar source to build the API surface\\.","errorType":"exception","errorClass":"GradleException","httpStatus":null,"severity":"error","filePath":"api-checker/gradle-plugins/src/main/java/org/apache/kafka/gradle/KafkaPublicApiCheckerTask.java","lineNumber":89,"sourceCode":"\n    @TaskAction\n    public void checkPublicApi() {\n        if (!getCheckerEnabled().get()) {\n            getLogger().info(\"KafkaPublicApiChecker is disabled, skipping...\");\n            return;\n        }\n\n        File jarFile = getJavadocJarFile();\n        if (!jarFile.exists()) {\n            throw new GradleException(\"Javadoc JAR file not found: \" + jarFile.getAbsolutePath() +\n                \". Make sure the javadoc task has run first.\");\n        }\n\n        getLogger().info(\"Checking public API consistency in: {}\", jarFile.getAbsolutePath());\n\n        try {\n            if (projectJarFiles.getFiles().isEmpty()) {\n                throw new GradleException(\n                        \"No project JARs configured on kafkaPublicApiChecker.projectJarFiles — \"\n                        + \"the checker needs at least one classes/jar source to build the API surface.\");\n            }\n            PublicApiChecker checker = new PublicApiChecker(\n                new ArrayList<>(projectJarFiles.getFiles()),\n                new ArrayList<>(referenceJarFiles.getFiles()));\n            CheckResult result = checker.checkPublicApiConsistency(jarFile);\n            List<PublicApiViolation> violations = result.violations();\n            List<PublicApiViolation> suppressions = result.suppressions();\n\n            // Generate report\n            ViolationReporter reporter = new ViolationReporter();\n            File report = reportFile.get().getAsFile();\n            reporter.writeTextReport(violations, suppressions, report);\n\n            // Print summary to console\n            reporter.printToConsole(violations, suppressions);\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/api-checker/gradle-plugins/src/main/java/org/apache/kafka/gradle/KafkaPublicApiCheckerTask.java#L71-L107","documentation":"Thrown by KafkaPublicApiCheckerTask.checkPublicApi() when projectJarFiles resolves to an empty file collection. The checker constructs its API surface from the classes/jars in projectJarFiles (line 93-95), so an empty collection means there is nothing to compare against the javadoc jar and the check is meaningless. Unlike javadocJarPath, projectJarFiles has no convention default — the build script or plugin must populate it explicitly.","triggerScenarios":"Line 88-92: projectJarFiles.getFiles().isEmpty() is true inside the try block. Reached when the plugin is applied without configuring kafkaPublicApiChecker.projectJarFiles, or when the configured from(...) source resolves to no files (e.g. a configuration that has no dependencies, or a tasks.named('jar') reference whose task has not produced output yet).","commonSituations":"Applying the plugin to a new subproject but forgetting to wire projectJarFiles.from(tasks.named('jar')); using a custom configuration that turned out empty; a multi-module root that applies the plugin to allprojects including ones that produce no main jar (e.g. aggregator/bom modules); renaming the jar task so the from(...) reference points at nothing.","solutions":["Wire projectJarFiles to the project's main jar output: kafkaPublicApiChecker.projectJarFiles.from(tasks.named('jar')).","If the module legitimately produces no jar (bom/aggregator), don't apply the plugin to that subproject — apply it inside a subprojects {} block filtered to modules with a jar task.","Confirm the source configuration actually has artifacts by printing it: println kafkaPublicApiChecker.projectJarFiles.files before the check.","If multiple outputs are needed, add them all: kafkaPublicApiChecker.projectJarFiles.from(tasks.named('jar'), configurations.runtimeClasspath.filter { it.name.startsWith('kafka') })."],"exampleFix":"// before\nplugins { id 'org.apache.kafka.kafka-public-api-checker' }\n// projectJarFiles never configured -> empty\n\n// after\nplugins { id 'org.apache.kafka.kafka-public-api-checker' }\n\nkafkaPublicApiChecker {\n  projectJarFiles.from(tasks.named('jar'))\n}","handlingStrategy":"validation","validationCode":"// Configure projectJarFiles from the project's own jar output\ntasks.named<org.apache.kafka.gradle.KafkaPublicApiCheckerTask>(\"kafkaPublicApiChecker\").configure {\n    projectJarFiles.from(tasks.named<Jar>(\"jar\").get().archiveFile)\n}\ncheck(tasks.named<org.apache.kafka.gradle.KafkaPublicApiCheckerTask>(\"kafkaPublicApiChecker\").get().projectJarFiles.files.isNotEmpty()) {\n    \"kafkaPublicApiChecker.projectJarFiles is empty; wire it to the project's jar/archive output.\"\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set projectJarFiles in the plugin configuration block to at least the project's main jar (tasks.jar output).","Apply the plugin only to projects that actually produce a jar; for pure BOM/platform projects skip it.","In multi-project builds, assert projectJarFiles is non-empty in a configuration-time check so the failure points at the right module."],"tags":["gradle","kafka","api-checker","configuration","classpath"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}