Nexus Gradle "Could not PUT ... received status code 401/400" on publish in CI
Gradle publishing failed the upload PUT. A 401 means the repositories { maven { credentials } } block sent no valid Nexus user/password; a 400 means you redeployed an immutable release. Read the status code to tell which.
What this error means
gradle publish fails with "Could not PUT 'https://nexus.example.com/repository/...'. Received status code 401 from server: Unauthorized" (or 400 Bad Request on a redeploy).
> Failed to publish publication 'maven' to repository 'nexus'
> Could not PUT
'https://nexus.example.com/repository/maven-releases/com/example/app/1.2.0/app-1.2.0.jar'.
Received status code 401 from server: UnauthorizedCommon causes
Missing or wrong credentials in the publish repo
The maven-publish repositories block has no credentials, or reads properties that are empty in CI, so Gradle sends an anonymous PUT and Nexus returns 401.
Redeploying a release (400)
A 400 on PUT is the release-repo immutability guard; the version already exists and cannot be overwritten.
How to fix it
Provide credentials from environment secrets
- Configure the publish repository with credentials from Gradle properties or env vars.
- Set those from CI secrets (NEXUS_USERNAME/NEXUS_PASSWORD).
- Re-run gradle publish.
publishing {
repositories {
maven {
name = "nexus"
url = uri("https://nexus.example.com/repository/maven-releases/")
credentials {
username = System.getenv("NEXUS_USERNAME")
password = System.getenv("NEXUS_PASSWORD")
}
}
}
}Bump the version for a 400 redeploy
If the status is 400, the release version already exists; increment the version instead of overwriting it.
How to prevent it
- Read publish credentials from env/secrets, never hardcode them.
- Publish releases only with new versions; use snapshots for iteration.
- Point the publish URL at a hosted repository.