Skip to content

Fix: Gradle Could Not Resolve Dependencies Error

FixDevs · (Updated: )

Part of:  Java & JVM Errors

Quick Answer

How to fix Gradle's 'Could not resolve all dependencies' error caused by missing repositories, offline mode, proxy issues, version conflicts, and corrupted cache.

The Resolver That Could Not Find the JAR

Personally, I think Gradle’s “Could not resolve dependencies” error is one of the most misread JVM build errors. The error message names a coordinate, not a cause; the actual fix depends on whether the coordinate is wrong, the repository is missing, the network is broken, or the cache is corrupted. I have learned to read the message URL before deciding which fix to apply. You run a Gradle build and it fails with:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Could not resolve all dependencies for configuration ':compileClasspath'.
   > Could not find org.springframework:spring-core:6.1.4.
     Searched in the following locations:
       - https://repo.maven.apache.org/maven2/org/springframework/spring-core/6.1.4/spring-core-6.1.4.pom
     Required by:
         project :

Or one of these variations:

Could not resolve all files for configuration ':runtimeClasspath'.
> Could not resolve com.google.guava:guava:33.0.0-jre.
  Required by:
      project :app
   > No matching variant of com.google.guava:guava:33.0.0-jre was found.
Could not resolve all dependencies for configuration ':app:debugCompileClasspath'.
> Could not find com.example:internal-lib:1.0.0.

The build stops. None of your dependencies download. Nothing compiles.

Quick Reference Before You Dive In

If you arrived here from Google with a fresh failure, the five facts that resolve roughly 90 percent of cases:

  1. Read the URL Gradle tried in Searched in the following locations: FIRST. Open it in a browser. 404 means the coordinate is wrong; 403 means auth required; hang means network broken; success means the cache is the problem. The Gradle dependency resolution documentation is the canonical reference.
  2. --refresh-dependencies only helps when the cache is stale. It does NOT fix typos, missing repositories, or proxy issues. Try other fixes first.
  3. Modern Gradle’s dependencyResolutionManagement in settings.gradle can SILENTLY override build.gradle repository declarations. Check settings.gradle before adding repositories to build.gradle.
  4. Behind a corporate proxy, set systemProp.https.proxyHost AND systemProp.http.proxyHost in gradle.properties. Configuring only one leaves the other protocol unproxied.
  5. No matching variant errors are Gradle Module Metadata variant rejection, NOT missing artifacts. Use gradle dependencyInsight --dependency <coord> to see which attributes (JDK target, OS, etc.) failed to match.

The rest of this article walks through each cause in detail, plus the failure modes most other guides skip.

Why Gradle Decides It Cannot Find the Artifact

Gradle resolves dependencies by searching repositories you declared in your build.gradle or build.gradle.kts file. When it cannot find an artifact in any of those repositories, it throws a “Could not resolve dependencies” error.

The root causes fall into a few categories:

  • Missing or misconfigured repositories. The dependency exists, but you have not told Gradle where to look for it.
  • Offline mode is enabled. Gradle is not allowed to reach the network, so it can only use what is already cached locally.
  • A proxy or firewall blocks the connection. Gradle tries to reach the repository but the network blocks it.
  • Version conflicts. Two or more dependencies pull in incompatible versions of the same transitive dependency.
  • Stale or corrupted local cache. Gradle cached a failed resolution and keeps reusing it instead of retrying.
  • The artifact genuinely does not exist. The version you specified was never published, or the group/artifact ID is wrong.
  • Multi-project build misconfiguration. A subproject dependency is not wired up correctly.

Each of these causes has a different fix. Work through the ones below in order.

Diagnostic Timeline

Engineers under deadline pressure go straight to gradle build --refresh-dependencies and lose another twenty minutes when it doesn’t help. Here is the order an experienced JVM engineer actually works through this.

Minute 0: Skip --refresh-dependencies. It only helps in one specific case: a cached negative result from a transient repository outage. If the artifact never existed at the URL Gradle searched, or if the network is broken at a lower layer, --refresh-dependencies just re-runs the same failing request. Do it after you have ruled out other causes, not before.

Minute 1: Read the URL Gradle actually tried. The error message includes a line like Searched in the following locations: - https://repo.maven.apache.org/maven2/.... Open that URL in a browser. If it returns 404, the artifact does not exist at that coordinate; your group/artifact/version is wrong, or the artifact is in a different repository. If it returns 403, the repository requires authentication. If the browser hangs, your network cannot reach the repo at all (proxy, firewall, or DNS).

Minute 3: Discriminate the four failure classes.

  1. Coordinate wrong: typo, retracted version, or moved to new group ID (javax to jakarta, redis.clients to io.lettuce).
  2. Repository missing: the artifact exists, but not in any repository you declared. JitPack, Spring Snapshots, and corporate Nexus instances are the usual missing entries.
  3. Network broken: corporate proxy, MITM cert, or Maven Central rate limit (yes, this is real; 429 responses are increasingly common from CI runners on shared IPs).
  4. Cache corruption: ~/.gradle/caches/modules-2/files-2.1/<group>/<artifact>/<version>/ contains a 0-byte .jar or a .pom that was truncated mid-download.

Minute 5: The wrong path: deleting ~/.gradle/caches. Tempting, but it nukes every project’s cache and your next build downloads 600 MB. Surgically delete only the broken artifact: rm -rf ~/.gradle/caches/modules-2/files-2.1/<group>/<artifact>/<version>/. If you cannot identify the culprit, then --refresh-dependencies first.

Minute 7: Check the proxy MITM cert. Corporate networks often inject a self-signed certificate. If Maven Central returns javax.net.ssl.SSLHandshakeException: PKIX path building failed, your JVM does not trust the corporate root CA. The fix is not disabling SSL verification (which some Stack Overflow answers shamefully recommend); that opens the door to MITM attacks. Import the certificate into the JVM truststore (keytool -importcert ...) or configure Gradle to use a custom truststore via systemProp.javax.net.ssl.trustStore in gradle.properties.

Minute 9: Check settings.gradle repository order. Modern Gradle’s dependencyResolutionManagement block in settings.gradle takes precedence over repositories { ... } in build.gradle. If settings.gradle declares RepositoriesMode.FAIL_ON_PROJECT_REPOS, any repository you added in build.gradle is silently ignored. Run gradle --info build and search for Repositories evaluated to see what Gradle actually used.

Minute 12: Inspect mavenLocal carefully. mavenLocal() is convenient but treacherous; a truncated artifact in ~/.m2/repository poisons every subsequent resolution. If mavenLocal() is in your repository list and you have ever run a partial Maven build, suspect it first. Either remove mavenLocal() for CI builds or wipe ~/.m2/repository/<group>/<artifact>/ for the failing coordinate.

Real root-cause distribution: roughly 30% typo in coordinates or wrong version, 25% missing repository (especially for JitPack or in-house Nexus), 20% proxy/firewall/MITM cert, 15% cache corruption (the part --refresh-dependencies actually fixes), 10% Gradle Module Metadata variant mismatch with the wrong JVM target. Work the list in that order.

When to Use Which Fix

The next eight sections cover the fixes in detail. The table below maps your symptom to the recommended fix.

Your symptomRecommended fixWhy
URL in error returns 404, or repo not declaredFix 1: declare the right repositoryMost common cause
--offline flag or property is setFix 2: disable offline modeCannot reach network
Behind corporate proxy / firewall / MITMFix 3: systemProp.{http,https}.proxyHost + truststoreNetwork blocked
Two libs require different transitive versionsFix 4: resolutionStrategy.force or strictlyConflict resolution
Cache contains stale 0-byte JARFix 5: --refresh-dependencies, surgically remove cached entryCache corruption
verification-metadata.xml checksum failedFix 6: regenerate with --write-verification-metadataLocked metadata stale
Need to exclude or replace a transitive depFix 7: exclude or dependencySubstitutionCannot fix by version pin alone
Multi-project subproject resolution failsFix 8: check settings.gradle + project() syntaxMulti-project wiring wrong

If multiple rows apply, pick the topmost one.

Fix 1: Check and Add the Correct Repository

Gradle only searches repositories you explicitly declare. If you depend on a library hosted on Maven Central but your build.gradle only declares google(), Gradle will never find it.

Open your build.gradle (or build.gradle.kts) and check the repositories block:

// build.gradle
repositories {
    mavenCentral()
    google()
}
// build.gradle.kts
repositories {
    mavenCentral()
    google()
}

If the dependency comes from a private or third-party repository, add it explicitly:

repositories {
    mavenCentral()
    maven {
        url = uri("https://jitpack.io")
    }
    maven {
        url = uri("https://your-company.com/maven-repo")
        credentials {
            username = project.findProperty("repoUser") ?: ""
            password = project.findProperty("repoPassword") ?: ""
        }
    }
}

Store credentials in ~/.gradle/gradle.properties, not in build.gradle:

repoUser=your-username
repoPassword=your-token

Note: In multi-project builds, repositories declared in the root build.gradle do not automatically apply to subprojects. You may need a subprojects or allprojects block:

allprojects {
    repositories {
        mavenCentral()
        google()
    }
}

Or, in newer Gradle versions, use the dependencyResolutionManagement block in settings.gradle:

// settings.gradle
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
        google()
    }
}

This centralizes repository declarations and prevents subprojects from adding their own, which reduces inconsistency.

Verify that the artifact actually exists in the repository. Open the repository URL in your browser and navigate to the group/artifact/version path. If it returns a 404, the artifact is not there and you need a different repository or version.

Fix 2: Disable Offline Mode

Gradle has an offline mode that prevents all network access. If it is enabled, Gradle can only resolve dependencies that are already in your local cache. Anything not cached will fail.

Check if you are passing the --offline flag:

# This forces offline mode
gradle build --offline

Remove the --offline flag and run the build again:

gradle build

Also check your gradle.properties for the offline flag:

# Remove or comment out this line
# org.gradle.offline=true

In IntelliJ IDEA, offline mode can be enabled through the Gradle settings. Go to Settings > Build, Execution, Deployment > Build Tools > Gradle and uncheck Offline work.

In Android Studio, check File > Settings > Build, Execution, Deployment > Gradle and make sure offline mode is disabled. Older versions of Android Studio had a dedicated toggle in the Gradle panel toolbar.

Fix 3: Configure Proxy and Firewall Settings

If you are behind a corporate proxy, Gradle cannot reach external repositories without proxy configuration. You will typically see connection timeouts or “unable to resolve” errors.

Add proxy settings to ~/.gradle/gradle.properties:

systemProp.http.proxyHost=proxy.example.com
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=your-username
systemProp.http.proxyPassword=your-password
systemProp.http.nonProxyHosts=localhost|127.0.0.1|*.internal.example.com

systemProp.https.proxyHost=proxy.example.com
systemProp.https.proxyPort=8080
systemProp.https.proxyUser=your-username
systemProp.https.proxyPassword=your-password

Warning: You must configure both http and https proxy settings separately. Configuring only one will leave the other protocol unproxied.

If your company uses a custom SSL certificate for MITM inspection, you may also need to import the certificate into the Java truststore that Gradle uses:

keytool -importcert -alias company-proxy \
  -file /path/to/company-cert.crt \
  -keystore $JAVA_HOME/lib/security/cacerts \
  -storepass changeit

Test connectivity by running:

gradle build --info 2>&1 | grep -i "proxy\|connect\|timeout"

This shows detailed connection logs. Look for timeout errors or proxy negotiation failures. If you see java.net.ConnectException or javax.net.ssl.SSLHandshakeException, the proxy or SSL configuration is the problem.

If you use Maven for other projects, note that Gradle’s proxy configuration is different from Maven’s settings.xml. They do not share proxy settings. See how to fix Maven dependency resolution errors for Maven-specific proxy setup.

Fix 4: Resolve Version Conflicts

When two dependencies require different versions of the same transitive dependency, Gradle’s default strategy picks the highest version. But sometimes the highest version is binary-incompatible with one of the consumers, and the build breaks with a different error downstream, or Gradle itself fails to resolve the conflict.

First, inspect the dependency tree to find the conflict:

gradle dependencies --configuration compileClasspath

This prints a tree showing every dependency and its transitive pulls. Look for version mismatches; lines ending with -> X.Y.Z show where Gradle changed a version:

+--- com.squareup.okhttp3:okhttp:4.12.0
|    \--- com.squareup.okio:okio:3.7.0
\--- some.library:that-needs-old-okio:1.0.0
     \--- com.squareup.okio:okio:2.10.0 -> 3.7.0

Here, okio 2.10.0 was requested but Gradle upgraded it to 3.7.0 because okhttp pulled the newer version. If that-needs-old-okio is not compatible with okio 3.x, you have a problem.

Force a specific version using a resolution strategy:

configurations.all {
    resolutionStrategy {
        force 'com.squareup.okio:okio:3.7.0'
    }
}

Or in Kotlin DSL:

configurations.all {
    resolutionStrategy {
        force("com.squareup.okio:okio:3.7.0")
    }
}

For more granular control, use strictly in the dependency declaration:

implementation('com.squareup.okio:okio') {
    version {
        strictly '3.7.0'
    }
}

If the conflict causes a NoSuchMethodError at runtime instead of a build-time failure, the resolution happened but picked an incompatible version. See how to fix Java NoSuchMethodError for runtime classpath debugging.

An invocation I rely on more than gradle dependencies: gradle dependencyInsight --dependency <name> --configuration compileClasspath. It walks the resolution graph for one specific artifact and explains exactly why Gradle picked the version it did, including which incoming constraint won. When the dependency tree is hundreds of lines deep, this is the only sane way to attribute a version selection.

Fix 5: Force Refresh Dependencies

Gradle caches dependency metadata and artifacts in ~/.gradle/caches/. If a download was interrupted or a repository returned a temporary error, Gradle may have cached a “not found” marker. Subsequent builds reuse this marker and keep failing even though the artifact is now available.

Force Gradle to re-download everything:

gradle build --refresh-dependencies

This flag tells Gradle to ignore cached metadata and re-check all repositories. It does not delete the cache; it just bypasses it for this build.

If --refresh-dependencies does not help, delete the cache manually:

# Delete the entire Gradle cache (all projects)
rm -rf ~/.gradle/caches/

# Delete only module metadata and artifacts
rm -rf ~/.gradle/caches/modules-2/

On Windows:

Remove-Item -Recurse -Force "$env:USERPROFILE\.gradle\caches\modules-2"

After deleting the cache, run the build again. Gradle will re-download everything from scratch.

Warning: Deleting ~/.gradle/caches/ removes caches for all Gradle projects on your machine, not just the current one. The next build for every project will be slower as it re-downloads everything. If you only want to clear a specific dependency, delete its folder under ~/.gradle/caches/modules-2/files-2.1/.

This is analogous to how Maven’s local repository can become corrupted: a half-downloaded artifact in ~/.m2/repository produces the same kind of opaque resolution failure even though the file exists on disk.

Fix 6: Fix the Dependency Cache with Locking and Verification

Gradle supports dependency verification and locking to prevent silent changes or corrupted artifacts. If your project uses these features and they are misconfigured, builds will fail with resolution errors.

Dependency Verification

If your project has a gradle/verification-metadata.xml file, Gradle checks downloaded artifact checksums against expected values. A mismatch causes a resolution failure:

Dependency verification failed for configuration ':compileClasspath'

To regenerate the verification metadata after adding or updating dependencies:

gradle --write-verification-metadata sha256 build

This updates gradle/verification-metadata.xml with the correct checksums for all current dependencies.

Dependency Locking

If your project uses dynamic versions (like 2.+ or latest.release) with dependency locking, Gradle pins resolved versions in lock files. When a locked version is no longer available, resolution fails.

Update the lock files:

gradle dependencies --write-locks

Or for a specific configuration:

gradle dependencies --configuration compileClasspath --write-locks

If you do not use dependency locking intentionally, check for activateDependencyLocking() in your build scripts and remove it:

// Remove this if you don't want locking
dependencyLocking {
    lockAllConfigurations()
}

Fix 7: Use Dependency Exclusions and Substitutions

Sometimes you cannot fix a dependency conflict by forcing a version. The problematic transitive dependency needs to be excluded entirely, or replaced with a different module.

Exclude a Transitive Dependency

If a library pulls in a dependency that conflicts with another part of your project, exclude it:

implementation('com.example:some-library:1.0.0') {
    exclude group: 'org.slf4j', module: 'slf4j-log4j12'
}

This is common with logging frameworks. Many libraries bundle a specific SLF4J binding, but your project uses a different one. Excluding the unwanted binding prevents the conflict.

For a project-wide exclusion:

configurations.all {
    exclude group: 'org.slf4j', module: 'slf4j-log4j12'
}

Substitute a Module

Gradle lets you replace one dependency with another. This is useful when a library has been renamed or when you want to redirect all references to a single implementation:

configurations.all {
    resolutionStrategy {
        dependencySubstitution {
            substitute module('org.old:deprecated-lib') using module('org.new:replacement-lib:2.0.0')
        }
    }
}

A common real-world use case is Jakarta EE migration, where javax.* packages were renamed to jakarta.*:

configurations.all {
    resolutionStrategy {
        dependencySubstitution {
            substitute module('javax.servlet:javax.servlet-api') using module('jakarta.servlet:jakarta.servlet-api:6.0.0')
        }
    }
}

A trap I have personally walked into more than once: excluding a transitive dependency without confirming another path provides it. The build succeeds because the dependency tree is satisfied; the runtime crashes with ClassNotFoundException because no JAR on the classpath actually contains the class. Before excluding, run gradle dependencies | grep <library> to confirm another path still pulls it in, or pair the exclusion with a direct dependency on a replacement. The corresponding runtime error chain is documented at Fix: Java ClassNotFoundException.

Use a Bill of Materials (BOM)

A BOM aligns versions across a set of related libraries. This eliminates most version conflicts within that set:

dependencies {
    implementation platform('org.springframework.boot:spring-boot-dependencies:3.2.4')
    implementation 'org.springframework:spring-core'
    implementation 'org.springframework:spring-web'
    // No version needed (the BOM controls it)
}

Spring Boot, AWS SDK, and Google Cloud all publish BOMs. If you are pulling in multiple libraries from the same ecosystem, use the BOM to avoid manual version alignment.

Fix 8: Fix Multi-Project Build Configuration

In Gradle multi-project builds, dependency resolution errors often come from incorrect project references or missing configuration in subprojects.

Incorrect Project Dependencies

If a subproject depends on another subproject, use the project() syntax:

// In subproject-b/build.gradle
dependencies {
    implementation project(':subproject-a')
}

Make sure the referenced project is listed in settings.gradle:

// settings.gradle
rootProject.name = 'my-app'
include 'subproject-a', 'subproject-b'

If you see Could not find project :subproject-a, the project name in settings.gradle does not match. Check for typos, case sensitivity, and path separators.

Composite Builds

If you use includeBuild for composite builds, the included build must publish the artifacts that consumers expect:

// settings.gradle
includeBuild('../shared-library') {
    dependencySubstitution {
        substitute module('com.example:shared-library') using project(':')
    }
}

Without the dependencySubstitution block, Gradle will try to resolve com.example:shared-library from remote repositories instead of the local build.

Buildscript Dependencies

If the error mentions buildscript classpath resolution, the problem is in your build plugin dependencies, not your project dependencies. Check the buildscript block:

buildscript {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:8.3.0'
    }
}

The buildscript block has its own separate repositories section. Adding mavenCentral() to the project repositories block does not help plugin resolution. You need it in both places.

For the plugins DSL (preferred in modern Gradle), ensure settings.gradle has the plugin repositories configured:

// settings.gradle
pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
        google()
    }
}

If your build is failing with a Spring Bean creation error after fixing dependencies, the versions you resolved may be incompatible. Double-check that all Spring-related dependencies use the same major version, or pin them with a Spring Boot BOM as shown in Fix 7.

Stranger Causes I Have Tracked Down

If none of the fixes above solved the error, try these:

Upgrade Gradle itself. Older Gradle versions have known bugs in dependency resolution, especially with Gradle Module Metadata and variant-aware resolution. Check your current version:

gradle --version

Upgrade with the wrapper:

gradle wrapper --gradle-version 8.7

Then run the build with the wrapper:

./gradlew build

Check the Gradle wrapper version. If your project uses gradlew, the wrapper version in gradle/wrapper/gradle-wrapper.properties controls which Gradle version runs. Make sure it matches what your build scripts expect:

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip

Run with debug output. The --info or --debug flags give detailed logs about which repositories Gradle checked, what HTTP responses it got, and why resolution failed:

./gradlew build --info

Search the output for the failing dependency name. You will see exactly which URLs Gradle tried and what response codes it got.

Check your Java version. Some dependencies require a minimum Java version. If you are running Java 8 but the dependency targets Java 17, Gradle may fail to resolve it because the metadata specifies a Java version constraint. Check your Java version with:

java -version

If you are using the wrong Java version, update JAVA_HOME or configure the toolchain in build.gradle:

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

Look for typos in coordinates. A surprising number of resolution errors come from simple typos in the group ID, artifact ID, or version number. Double-check every character in the dependency declaration against the library’s official documentation or its page on Maven Central.

Check if the artifact was removed or relocated. Libraries sometimes change their Maven coordinates when they move to a new organization or undergo a major rewrite. Check the library’s GitHub repository or release notes for migration guides.

Look for Maven Central rate limiting on CI. Maven Central enforces rate limits on shared IPs. CI runners on GitHub Actions, GitLab SaaS, and CircleCI hit these limits regularly during peak hours. The symptom is intermittent Could not GET errors with HTTP 429 (sometimes masked as a generic timeout). Configure a mirror (Maven Central’s CDN mirror at https://repo1.maven.org/maven2/, Google’s Maven Central mirror, or your own Nexus / Artifactory) to avoid the shared rate bucket. Add it as the first repository in your resolution order so it is hit before mavenCentral().

Inspect Gradle Module Metadata variant rejection. Gradle 6+ uses Gradle Module Metadata (.module files) to expose multiple variants of an artifact (JVM, Android, native, JDK 8 vs JDK 17). The error No matching variant of com.example:lib:1.0 means the artifact exists but does not publish a variant compatible with your project’s attributes. Run gradle dependencyInsight --dependency com.example:lib --configuration runtimeClasspath and look for the “Variant selection failures” section; it lists which attributes did not match. Common cause: your project targets JDK 17 but the artifact only ships a JDK 21 variant.

Check the Gradle daemon for cached configuration. The Gradle daemon caches build script evaluation. If you edit build.gradle to add a repository but the daemon does not pick up the change, builds still fail with the old configuration. Force a daemon restart:

./gradlew --stop
./gradlew build

This is faster than restarting your machine and is the right first move whenever Gradle’s behavior seems inconsistent with what is in the build files.

Look for settings.gradle RepositoriesMode.FAIL_ON_PROJECT_REPOS. This mode rejects any repositories { ... } block in subproject build.gradle files. If you migrated from per-project repositories to centralized ones, leftover declarations in subprojects either fail loudly (good) or are silently ignored (bad, depending on Gradle version). Centralize all repositories in settings.gradle’s dependencyResolutionManagement block to avoid the ambiguity.

Confirm gradle.properties is being loaded. Settings in ~/.gradle/gradle.properties apply globally, settings in <project>/gradle.properties apply per project. The project file wins. If you set proxy settings globally but a project’s local gradle.properties lacks them, that project cannot reach external repositories. Print the effective properties with gradle properties | grep -i proxy to verify.

What Other Tutorials Get Wrong About This Error

Most Gradle tutorials list the same fixes but frame them in ways that produce subtle bugs.

They recommend --refresh-dependencies as the first move. It only fixes one of the four failure classes (cached stale metadata). For wrong coordinates, missing repositories, or proxy issues, it re-runs the same failing request. Read the error URL first; reach for refresh after diagnosis.

They show rm -rf ~/.gradle/caches/ as a “nuclear” fix. It works but nukes every project’s cache on the machine. Surgical removal of just the broken artifact (~/.gradle/caches/modules-2/files-2.1/<group>/<artifact>/<version>/) takes seconds; the wholesale wipe costs you hundreds of MB of re-downloads.

They miss RepositoriesMode.FAIL_ON_PROJECT_REPOS semantics. Modern Gradle’s dependencyResolutionManagement block in settings.gradle can SILENTLY override repository declarations in build.gradle. Tutorials that only show build.gradle repository blocks leave readers wondering why their declarations are ignored.

They omit MITM proxy diagnostics. “Could not resolve” behind a corporate proxy is almost always either an unconfigured proxy or an untrusted MITM root CA. Articles that recommend org.gradle.security.ssl.disable=true (or similar) teach insecure workarounds; the right answer is to import the corporate CA into the JVM truststore.

They confuse “No matching variant” with “Could not find.” “Could not find” means the artifact does not exist at the searched URL. “No matching variant” means the artifact exists but does not expose a variant compatible with your project’s attributes (JDK target, OS, etc.). The fixes are completely different.

They miss mavenLocal() poisoning. A truncated artifact in ~/.m2/repository poisons every subsequent resolution that includes mavenLocal(). Articles that show mavenLocal() as a convenience without warning about its hazards send readers debugging “Maven Central is down” when the local cache is the cause.

Frequently Asked Questions

Why does --refresh-dependencies sometimes fix it and sometimes not?

It only helps when the local Gradle cache contains stale metadata, typically from a transient repository outage that returned 404 once and got cached. For all other causes (wrong coordinates, missing repository, network issues, variant mismatch), the flag re-runs the same failing request. Read the error URL first; refresh is the last fix to try, not the first.

What is the difference between force and strictly in version constraints?

force (in resolutionStrategy) wins over any other version selection in that configuration; if another dependency is incompatible, your build fails at compile time. strictly (in dependencies) is a hard upper or lower bound that participates in conflict resolution but does not override; if another dep requires an incompatible version, you get a clear error explaining the conflict. Use strictly first for clearer error messages.

Why does my CI fail with “Could not resolve” but local builds succeed?

Three common causes. First, the CI runner does not have network access to your private repository (missing credentials or VPN). Second, the CI is rate-limited by Maven Central (HTTP 429 on shared IPs). Third, the CI uses --no-daemon or a fresh cache while local reuses a warm cache. Configure a repository mirror, ensure credentials are passed, and consider using Gradle’s build cache.

Should I commit gradle.properties with credentials?

No. Credentials belong in ~/.gradle/gradle.properties (user-level) or in CI secrets, never committed to the repository. The project-level gradle.properties should contain only repository-agnostic configuration. Many security incidents start with committed credentials in gradle.properties files.

What is the difference between mavenCentral() and mavenLocal()?

mavenCentral() resolves from the public Maven Central repository (https://repo.maven.apache.org/maven2/). mavenLocal() resolves from your local Maven cache at ~/.m2/repository/. The latter is useful for testing locally-installed artifacts but dangerous in CI because the cache contents are unpredictable. Avoid mavenLocal() in production builds.

Is --offline ever useful?

Yes, for reproducibility checks. If your build succeeds with --offline, you have proven that the build does not depend on any non-cached artifact. This is a useful CI check for verifying the build artifact is hermetic. For normal development, however, leave offline mode disabled.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles