{"record":{"id":"59301c80cc2e1a6c","repo":"opendataloader-project/opendataloader-pdf","slug":"found-multiple-jar-files-expected-one-source-ja","errorCode":null,"errorMessage":"Found multiple JAR files, expected one: {source_jar_paths}","messagePattern":"Found multiple JAR files, expected one: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/opendataloader-pdf/hatch_build.py","lineNumber":51,"sourceCode":"        ):\n            print(\"All required files already exist (building from sdist), skipping copy\")\n            return\n\n        # --- Copy JAR ---\n        print(f\"Root DIR: {root_dir}\")\n        source_jar_glob = str(\n            root_dir / \"../../java/opendataloader-pdf-cli/target/opendataloader-pdf-cli-*.jar\"\n        )\n        resolved_glob_path = Path(source_jar_glob).resolve()\n        print(f\"Searching for JAR file in: {resolved_glob_path}\")\n\n        source_jar_paths = glob.glob(source_jar_glob)\n        if not source_jar_paths:\n            raise RuntimeError(\n                f\"Could not find the JAR file. Please run 'mvn package' in the 'java/' directory first. Searched in: {resolved_glob_path}\"\n            )\n        if len(source_jar_paths) > 1:\n            raise RuntimeError(f\"Found multiple JAR files, expected one: {source_jar_paths}\")\n        source_jar_path = source_jar_paths[0]\n        print(f\"Found source JAR: {source_jar_path}\")\n\n        dest_jar_dir.mkdir(parents=True, exist_ok=True)\n        print(f\"Copying JAR to {dest_jar_path}\")\n        shutil.copy(source_jar_path, dest_jar_path)\n\n        # --- Copy LICENSE, NOTICE ---\n        # README is copied by build-python.sh before this hook runs, because\n        # hatchling validates [project.readme] during metadata parsing, which\n        # happens before build hooks. Do not copy README here.\n        shutil.copy(root_dir / \"../../LICENSE\", license_path)\n        shutil.copy(root_dir / \"../../NOTICE\", notice_path)\n        third_party_src = root_dir / \"../../THIRD_PARTY\"\n        print(f\"Copying THIRD_PARTY directory to {third_party_dest}\")\n        if third_party_dest.exists():\n            shutil.rmtree(third_party_dest)\n        shutil.copytree(third_party_src, third_party_dest)","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/python/opendataloader-pdf/hatch_build.py#L33-L69","documentation":"RuntimeError raised by the hatch build hook when glob.glob matched MORE THAN ONE jar under java/opendataloader-pdf-cli/target/opendataloader-pdf-cli-*.jar. The hook expects exactly one (the current version) so it can copy it deterministically into the wheel; multiple matches usually mean stale jars from prior versions are sitting next to the new one.","triggerScenarios":"Running the Python build when target/ contains several versioned jars — e.g. opendataloader-pdf-cli-1.0.0.jar and opendataloader-pdf-cli-1.1.0.jar — because mvn clean was not run between version bumps or SNAPSHOT jars accumulated.","commonSituations":"Version bump without mvn clean leaves the old jar. Concurrent/parallel Maven runs in the same target. Release artifacts left from a prior release build. SNAPSHOT + release jars coexist.","solutions":["Clean and rebuild: run mvn clean package in java/, then rebuild the wheel so exactly one jar remains.","Manually remove stale jars from java/opendataloader-pdf-cli/target/ matching the glob, leaving only the current version.","Pin the build to mvn clean package in CI so target/ is always fresh before the wheel build."],"exampleFix":"# before: stale jars accumulate\n$ ls java/opendataloader-pdf-cli/target/*.jar\nopendataloader-pdf-cli-1.0.0.jar  opendataloader-pdf-cli-1.1.0.jar\n# after: clean rebuild yields a single jar\n$ (cd java && mvn clean package)\n$ ls java/opendataloader-pdf-cli/target/*.jar\nopendataloader-pdf-cli-1.1.0.jar","handlingStrategy":"validation","validationCode":"# Pre-build check enforcing exactly one jar:\nimport glob\njars = glob.glob(\"java/opendataloader-pdf-cli/target/opendataloader-pdf-cli-*.jar\")\nif len(jars) > 1:\n    raise SystemExit(f\"Multiple jars found {jars}; run: (cd java && mvn clean package)\")\n","typeGuard":"def is_multiple_jar_error(exc: RuntimeError) -> bool:\n    return isinstance(exc, RuntimeError) and \"Found multiple JAR files\" in str(exc)","tryCatchPattern":"# CI step: clean before package so target/ has exactly one jar.\n#   (cd java && mvn clean package) && pip install .\n","preventionTips":["Use mvn clean package (not just mvn package) on version bumps so stale jars are removed.","In CI, never reuse target/ across versions without cleaning.","Glob and assert exactly one jar before invoking the wheel build."],"tags":["build","hatch","maven","jar","packaging","stale-artifacts"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}