Your build dies before the app ever runs: the task :app:transformClassesWithJarMergingForDebug stops with java.util.zip.ZipException: duplicate entry and names one class file from a barcode decoding core. Nothing is wrong with your code. Two dependencies on the classpath carry the same class file, and the jar merge refuses to write the same archive path twice. It bites hardest in apps that both scan barcodes and generate QR images, because QR-generator libraries tend to bundle the decoding classes that a scanner library already pulls in. Here you will learn to read the error, find both copies with a zip listing and a dependency report, and fix the build while keeping both features on one decoding core.
Read the error before you touch the build file
Every part of the message points somewhere specific. transformClassesWithJarMergingForDebug is the Android Gradle plugin step that merges every jar on the classpath into the dex inputs; the failure happens there, before your own classes are even in question. ZipException: duplicate entry is the zip layer refusing to write the same archive path twice. And the path itself — com/google/zxing/aztec/AztecDetectorResult.class — names the package tree (the decoding core), the symbology package (aztec) and the class (the Aztec detector's result object).
The named class is the first collision the merger reaches, not the only duplicate and not a class your code calls. Fix the pair of artifacts that own that package tree and the error clears; any further collision surfaces on the next build.
The dex settings in a build file like this one are bystanders. multiDexEnabled true, javaMaxHeapSize "4g" and preDexLibraries = false all act on dexing: how many dex files get written and how much memory the step receives. The duplicate check runs earlier, while the archives are still merging, so no flag combination clears this error. The classpath does.
The three ways a class ends up in the build twice
Ranked by how often each explains this exact signature:
- One artifact bundles another's classes. The QR-generator artifact carries the decoding core's classes inside its own archive, while the barcode-scanner artifact pulls the same core as a declared dependency. No edge connects the two in the dependency graph, so version resolution never collapses the copies, and the merge sees both.
-
A manual jar in libs/ duplicates a managed artifact. The line
fileTree(dir: 'libs', include: ['*.jar'])adds every jar in that folder outside version resolution. If one of those jars repeats a dependency you also declare by coordinates, the merge sees two copies. - Two declarations pull the same transitive artifact. Rarer on current tooling, but real when one line pins an old version or both the library and its core are declared explicitly.
For the failing list here — a QR generator and a barcode scanner that both revolve around one decoding core — cause 1 is the likely one, and the tests below confirm it in minutes.
Test each cause in two minutes
- Open the suspect artifact as a zip. An .aar and a .jar are zip archives; list the entries and search for the colliding package path. Entries of that path inside the generator's own archive mean the classes are bundled, and no Gradle exclude reaches them. No such entries mean the copy arrives through the graph, and an exclude works.
-
Print the dependency graph.
gradlew app:dependenciesshows every declared artifact and its children. A core that appears both as a direct line and as a child of another line is a graph duplicate. - Audit libs/. Match each jar in the folder against your declared coordinates. One match is a duplicate by construction, and the jar is the copy to remove.
The fix for each cause
- Graph duplicate: exclude the transitive artifact on the line that pulls it, using that group/module pair; or delete your explicit line and keep the version the graph resolves to. Rebuild — the merge either passes or names the next pair.
- libs/ duplicate: delete the jar and keep the managed line. The declared dependency gets version resolution and updates; the manual jar gets neither.
- Bundled copy, which is this case: an exclude does nothing because the classes sit physically inside the other archive. Decide who owns the capability and remove the other artifact entirely. Here the scanner stays, because the app calls its camera preview and its decode results at run time. The generator goes, and its surviving job — painting a QR image — is rebuilt on the encoder inside the core you kept, in a few lines of bitmap code (next section).
If decoding misbehaves afterwards — empty results on Aztec symbols, for instance — that is a content failure, not a build one; the empty-decode diagnosis guide picks it up from there.
Worked example: keep both features on one decoding core
The removed generator did two jobs: encode content into a QR matrix, and paint the matrix as an image. Encoding is already in the core the scanner pulls; its QR writer class takes your string and returns a BitMatrix. Painting is ordinary bitmap code. In the snippet, payload is your own String to encode; writer, matrix, side, pixels and qrImage are declared with their types:
QRCodeWriter writer = new QRCodeWriter(); // from the kept core
BitMatrix matrix = writer.encode(payload, BarcodeFormat.QR_CODE, 512, 512);
int side = matrix.getHeight(); // 512
int[] pixels = new int[side * side]; // 262,144 ints
for (int y = 0; y < side; y++) {
for (int x = 0; x < side; x++) {
pixels[y * side + x] = matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF;
}
}
Bitmap qrImage = Bitmap.createBitmap(pixels, side, side, Bitmap.Config.ARGB_8888);
Resist the one-pixel setter: calling Bitmap.setPixel 262,144 times takes visibly longer than one createBitmap call with the finished buffer.
The test that proves it: display qrImage or save it as a PNG, then scan the rendered code with the scanner you kept. If the decode returns payload unchanged, both features now run on one artifact. When you decode camera frames in your own code, keep the pixel buffer intact until the decode returns — the pixel-buffer guide shows how copies and conversions break reads.
When the decode belongs in the reader, not the app
If this build serves a production or logistics station rather than a pocket app, the sturdiest fix removes the decode from your classpath altogether. A fixed code reader carries its decoder in firmware, reads the code in front of it and hands your application a validated string over its Ethernet link. Nothing to merge, and a decode engine tuned for the job. Browse fixed code readers by interface and resolution in the camera finder.
- Interface
- Fast Ethernet
- Resolution
- Up to 3 MP
- Interface
- Fast Ethernet
- Resolution
- 5 MP
The MV-ID3013PM-12M-WBN covers compact installations with a 1.3 MP sensor and a 12 mm focal length. The LS-CRD-0028 pairs a 2560 x 2048 global-shutter sensor with an 8 mm lens and reads up to 60 codes/s at 30 fps, for lines where parts move past continuously.
When the same station also inspects the image itself, an on-device smart camera does that job without a PC and without decode or imaging libraries in your build. The rest of the range sits in smart cameras.
- Interface
- GigE
- Resolution
- 6-10 MP
- Sensor format
- 1/2.4"
- Shutter
- Rolling
The MV-SC5060XM-08M-WBN inspects 6 MP mono frames on the device through its 8 mm M12 lens. The camera decoding walkthrough follows the full path from frame to validated data, and the configurator, started at the camera step, walks working distance, code size and interface in order.
Prevention checklist
- One owner per capability. Decoding lives in exactly one declared artifact; encoding and rendering reuse it. Two artifacts that both "do barcodes" is the failure mode behind this whole error.
- No manual jars beside managed ones. If a capability exists as a declared dependency, the libs/ copy goes; if it exists only as a jar, the managed line for it goes.
- Build after every dependency change. The merge fails at the first collision, so a quick build after each addition names the next pair before you write feature code on top of it.
- Read the report the newer tooling gives you. Current Android Gradle plugin lines surface the same clash as a duplicate-class check that names both artifacts and their versions. When a maintenance window allows a plugin upgrade, this hunt shrinks to reading one error line.
- Carry the one-version rule across the stack. The same discipline that fixes this build governs SDKs and firmware on the vision side; the one-library-version guide applies it to Docker builds for vision software.
More build and integration failures sit on the systems topic page. If you would rather move the decode off your classpath entirely, contact the applications team with your reading distance and code type, and we will match a reader to the line.
Questions
Why does the error name an Aztec class when my app never scans Aztec codes?
The jar merge stops at the first colliding file in the order it walks the archives, not at a class your code calls. The Aztec detector result class ships inside the decoding core that every barcode library carries, so it collides even when no Aztec symbol is ever decoded. Clear the pair that owns that core and the error disappears, whatever symbologies you scan.
Are multiDexEnabled true and the multidex library part of the problem?
They are correct as written. With minSdkVersion 14 the runtime handles multiple dex files natively only from API 21 upward, so the legacy multidex support is required below that. The duplicate check fails during the jar merge, before multidex settings or dex memory play any part, so raising javaMaxHeapSize or toggling multidex cannot clear it.
Can a Gradle exclude remove the copy bundled inside the QR generator's jar?
Only when the duplicate arrives through the dependency graph, as a declared dependency of the generator. Then an exclude carrying the group and module of the decoding core, placed on the generator's line, removes it. When the generator physically bundles the classes inside its own archive, no exclude reaches them; swap to a published variant that leaves the decoder out, or drop the generator and render the QR image from the core you keep.
Which artifact should keep the shared decoding core, the scanner or the generator?
The scanner, because its classes are the ones your code calls at run time: camera preview, decode configuration and result delivery all hang off it. The generator only needs the encoder, which sits in the same core, plus a few lines of bitmap code to paint the matrix. Removing the scanner instead leaves a build that compiles and then fails at the first scan.
I have the decoding jar in libs/ and a managed line for the same library. Which stays?
Keep the managed artifact and delete the jar. A declared dependency takes part in version resolution and appears in dependency reports; a jar dropped into libs/ does neither, which makes every future classpath hunt harder. If the class exists only in that jar, invert the decision and drop the managed line instead: one owner per artifact, never both.


