In this article
A duplicate Android version code is an artifact identity problem: the submitted bundle contains a code Google Play has already seen. Inspect the bundle and the previous upload before rerunning CI. A successful rebuild with the same code does not create a new upload identity.
Android's versioning guide, checked October 8, 2026, distinguishes the integer versionCode from the user-visible versionName. The version name alone cannot solve a version-code rejection.
Inspect the uploaded object#
Record the package name, version code, version name, checksum and CI run that produced the bundle. Use your established artifact inspection tool to read the effective values; a source-file value may have been overridden by build arguments or a flavor.
Compare the checksum with the file submitted by the upload step. Pipelines sometimes build one path and upload an older artifact from another path.
Then find the existing provider record for that code. Include testing tracks in the investigation. “It is not in production” does not prove a code has never been uploaded.
Classify the retry correctly#
Three incidents look similar but require different responses:
- Upload outcome uncertain: a network error occurred after submission. Check whether the provider accepted the artifact before sending it again.
- Wrong artifact selected: the pipeline uploaded an older file. Correct the path and inspect the intended file.
- New build reused an existing code: allocate a valid new code and rebuild, then verify it in the result.
Do not increment blindly after every timeout. That hides the original outcome and can create several redundant releases.
Allocate numbers across all upload paths#
Google's versioning rules require appropriate increasing codes for updates and document the supported numeric range. A branch-local counter can collide when two branches or workflows upload the same app.
Choose a single allocation mechanism for the application. It could be a durable counter or another monotonic scheme your release system can validate. Account for manual builds, hotfix branches, migrated workflows and retries. A job number is safe only if you have proved its uniqueness and ordering across every relevant path.
A useful reservation record is:
Application:
Reserved version code:
Release source revision:
Allocation owner:
Build artifact checksum:
Upload attempt/result:Reserve before building. If a build fails, do not recycle a number merely to keep the sequence gap-free; gaps are easier to manage than uncertainty about whether a number was used.
Correct the configuration layer that wins#
For Flutter, review the version declaration and any --build-number supplied by CI. For native Android configuration, inspect flavor or build-type overrides. The relevant question is which value reached the artifact, not which file looks easiest to edit.
For a hypothetical build using code 205:
flutter build appbundle --release --build-number=205This is an example, not a safe next code for your app. Verify availability and your project's complete release arguments before using a number.
Close the incident with provider evidence#
Confirm the rebuilt bundle contains the allocated code and the correct package, then upload through the normal authorized release process. Record whether the provider accepted it and which track or release record owns it.
Build, upload and store publication remain separate states. Our CascadeCI overview explains that distinction. A corrected number should resolve the identified rejection, not be reported as proof that the app is live.