Skip to content
Latchkey

Gradle "Failed to publish ... 401 Unauthorized" - Fix Publishing Auth in CI

Gradle authenticated to the publish target and was rejected with a 401. The publishing block sent no credentials or the wrong ones - the repository credentials {} is missing, or the CI secret holding the token is absent or stale.

What this error means

A publish/publishAllPublicationsTo...Repository task fails with Could not PUT '<url>'. Received status code 401 from server: Unauthorized. Resolution from the same repo works; only the upload fails.

gradle output
> Task :app:publishMavenPublicationToReleasesRepository FAILED
> Failed to publish publication 'maven' to repository 'releases'
   > Could not PUT 'https://nexus.example.com/.../app-1.0.0.jar'.
     Received status code 401 from server: Unauthorized

Common causes

No credentials on the publish repository

The maven { url = ... } repository in the publishing block has no credentials {} (or empty values), so Gradle uploads unauthenticated and the server returns 401.

Wrong or missing CI secret

The username/token is read from environment variables or Gradle properties that are not set in CI, or the token has expired, so authentication fails.

How to fix it

Add credentials from CI secrets to the publish repo

Wire the username/token into the publishing repository, sourced from CI environment variables.

build.gradle.kts
publishing {
    repositories {
        maven {
            name = "releases"
            url = uri("https://nexus.example.com/repository/maven-releases/")
            credentials {
                username = System.getenv("REPO_USER")
                password = System.getenv("REPO_TOKEN")
            }
        }
    }
}

Confirm the secret is injected into the job

Make sure the CI step actually exposes the token to the Gradle process.

.github/workflows/ci.yml
- run: ./gradlew publish
  env:
    REPO_USER: ${{ secrets.REPO_USER }}
    REPO_TOKEN: ${{ secrets.REPO_TOKEN }}

How to prevent it

  • Always declare credentials {} on publish repositories, sourced from CI secrets.
  • Use a write/deploy-scoped token for publishing, separate from read tokens.
  • Rotate publish tokens and confirm they are injected into the job env.

Frequently asked questions

What causes ""Could not PUT ... 401 Unauthorized""?
The maven { url = ... } repository in the publishing block has no credentials {} (or empty values), so Gradle uploads unauthenticated and the server returns 401.
How do I fix "Could not PUT ... 401 Unauthorized"?
Wire the username/token into the publishing repository, sourced from CI environment variables.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card