Fix: Maven Could Not Resolve Dependencies - Failed to Read Artifact Descriptor
Part of: Java & JVM Errors
Quick Answer
How to fix Maven's 'Could not resolve dependencies' and 'Failed to read artifact descriptor' errors caused by corrupted cache, proxy settings, missing repositories, and version conflicts.
The Error
You run mvn clean install or mvn package and the build fails with:
[ERROR] Failed to execute goal on project my-app:
Could not resolve dependencies for project com.example:my-app:jar:1.0.0:
Failed to read artifact descriptor for org.springframework:spring-core:jar:6.1.4:
Could not transfer artifact org.springframework:spring-core:pom:6.1.4
from/to central (https://repo.maven.apache.org/maven2):
Transfer failed for https://repo.maven.apache.org/maven2/org/springframework/spring-core/6.1.4/spring-core-6.1.4.pomOr a variation like:
[ERROR] Failed to execute goal on project my-app:
Could not resolve dependencies for project com.example:my-app:jar:1.0.0:
The following artifacts could not be resolved:
org.some.library:some-artifact:jar:2.3.1 (absent):
Could not find artifact org.some.library:some-artifact:jar:2.3.1 in central
(https://repo.maven.apache.org/maven2)Or sometimes:
[ERROR] Non-resolvable parent POM for com.example:my-module:1.0.0:
Could not transfer artifact com.example:parent-pom:pom:1.0.0
from/to internal-repo (https://nexus.company.com/repository/maven-public/):
Authentication failed for https://nexus.company.com/repository/maven-public/The build stops and nothing compiles. Every dependency-related task fails until you fix the underlying cause.
Why This Happens
Maven resolves dependencies by downloading JAR and POM files from remote repositories into your local cache (~/.m2/repository). The “Could not resolve dependencies” error means Maven tried to fetch or read an artifact and failed.
There are several root causes:
- Corrupted local cache: A previous download was interrupted, leaving broken JAR or POM files in
~/.m2/repository. Maven sees the file exists and tries to read it, but the content is garbage. - Network or proxy issues: You are behind a corporate firewall or HTTP proxy, and Maven cannot reach Maven Central or your internal repository.
- Wrong mirror or repository configuration: Your
settings.xmlpoints to a mirror that is down, misconfigured, or requires authentication you have not provided. - The artifact does not exist: The dependency version you specified was never published. A typo in the
groupId,artifactId, orversionis enough. - Parent POM not available: Your project inherits from a parent POM that Maven cannot find, either because it is not in the repo or not installed locally.
- Version conflicts: Two dependencies pull in incompatible versions of the same transitive dependency, and Maven cannot reconcile them.
- Repository policy blocks snapshots or releases: The repository configuration only allows releases, but you are requesting a SNAPSHOT version (or vice versa).
Each cause has a different fix. Work through them in order; most dependency resolution failures fall into the first three categories.
Fix 1: Force Update Dependencies with the -U Flag
Maven caches download failures. If an artifact failed to download once, Maven marks it as “not found” and will not retry for a set period (usually daily). The -U flag forces Maven to check remote repositories again:
mvn clean install -UThis tells Maven to update snapshots and release policies, ignoring the cached failure markers. If the issue was a temporary network blip or a repository that was briefly unavailable, this single flag resolves it.
Note: The -U flag only forces re-checking remote repositories. It does not fix corrupted files already in your local cache. If the problem persists after -U, move to Fix 2.
Fix 2: Clear Corrupted Local Repository Cache
A corrupted ~/.m2/repository is the most common cause. Partial downloads, interrupted builds, or disk errors leave behind broken files that Maven cannot parse.
Delete the Specific Artifact
Find the problem artifact from the error message and delete its folder. For example, if the error mentions org.springframework:spring-core:6.1.4:
rm -rf ~/.m2/repository/org/springframework/spring-core/6.1.4Then rebuild:
mvn clean installMaven re-downloads the artifact from scratch.
Delete the Entire Dependency Cache
If multiple artifacts are corrupted or you are unsure which ones are broken, nuke the entire local repository:
rm -rf ~/.m2/repositoryThen rebuild. Maven re-downloads everything. This takes longer but guarantees a clean state.
Pro Tip: Before deleting the whole
~/.m2/repository, check its size. On large projects it can be several gigabytes. If you are on a slow connection, delete only the affected artifact folders first. You can also look for files ending in.lastUpdatedinside~/.m2/repository- these are failure markers from previous download attempts. Deleting them has the same effect as-Ubut is more targeted:find ~/.m2/repository -name "*.lastUpdated" -delete
Check for _remote.repositories Files
Maven stores metadata about where each artifact was downloaded from in _remote.repositories files. If you switch between repositories (for example, from a corporate Nexus to Maven Central), these files can cause conflicts. Delete them alongside the artifact:
find ~/.m2/repository -name "_remote.repositories" -deleteFix 3: Fix Your settings.xml Configuration
Maven reads configuration from two locations:
- Global:
${MAVEN_HOME}/conf/settings.xml - User:
~/.m2/settings.xml
User settings override global settings. Misconfigurations here cause most corporate environment failures.
Locate Your Active settings.xml
Check which settings file Maven is actually using:
mvn help:effective-settingsThis prints the merged result of all settings files. Look for unexpected mirrors, proxies, or servers.
Fix Mirror Configuration
A mirror intercepts all requests to a given repository and redirects them. If your mirror is down or misconfigured, every dependency resolution fails.
A correct mirror configuration in ~/.m2/settings.xml looks like:
<settings>
<mirrors>
<mirror>
<id>company-mirror</id>
<name>Company Nexus</name>
<url>https://nexus.company.com/repository/maven-public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>Common issues:
mirrorOfset to*: This redirects all repository requests through the mirror, including any custom repositories defined in yourpom.xml. If the mirror does not proxy those repositories, the artifacts will not be found. Change*tocentralor a specific list.- Wrong URL: Verify the mirror URL by opening it in a browser. You should see a repository index or at least get a response from the server.
- Missing authentication: If the mirror requires credentials, add a
<server>block (see below).
Fix Server Authentication
If your repository requires authentication, you need a matching <server> entry where the <id> matches the repository or mirror <id>:
<settings>
<servers>
<server>
<id>company-mirror</id>
<username>your-username</username>
<password>your-password</password>
</server>
</servers>
</settings>Note: Storing passwords in plain text is a security risk. Use Maven’s password encryption to encrypt credentials in settings-security.xml.
Fix 4: Configure Proxy Settings for Corporate Networks
Behind a corporate proxy, Maven cannot reach Maven Central unless you explicitly configure the proxy. This is a frequent issue in enterprise environments and the error often looks like a timeout or connection refused. If you are also seeing SSL-related errors behind a proxy, check out how to fix SSL certificate problems which covers certificate trust issues in detail.
Add this to your ~/.m2/settings.xml:
<settings>
<proxies>
<proxy>
<id>company-proxy</id>
<active>true</active>
<protocol>https</protocol>
<host>proxy.company.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>proxypassword</password>
<nonProxyHosts>localhost|127.0.0.1|*.company.com</nonProxyHosts>
</proxy>
</proxies>
</settings>Key details:
- Set
protocoltohttpsif Maven Central (or your mirror) uses HTTPS. You may need a second<proxy>block forhttpif some repos use plain HTTP. nonProxyHostsexcludes internal hosts from the proxy. Use|as a separator and*for wildcards. Always include your internal repository hostname here.- If your proxy does not require authentication, omit the
<username>and<password>fields.
You can verify your proxy is working by running Maven with debug output:
mvn clean install -XLook for lines mentioning “proxy” in the output. Maven logs which proxy it uses for each connection.
Fix 5: Add Missing Repositories to Your pom.xml
If the artifact is not on Maven Central, you need to tell Maven where to find it. Some libraries are hosted on custom repositories (JBoss, Spring Milestones, Atlassian, etc.).
Add the repository to your pom.xml:
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>If the artifact is a Maven plugin, use <pluginRepositories> instead:
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>Common Mistake: Adding a repository in
pom.xmlwhile having a<mirrorOf>*</mirrorOf>in yoursettings.xml. The mirror intercepts the custom repository request and tries to find the artifact in the mirror, which does not have it. Either change the mirror’smirrorOftocentralor add the custom repository to your mirror’s proxy group (in Nexus/Artifactory).
Fix 6: Fix Dependency Version Conflicts
When two dependencies pull in different versions of the same transitive dependency, Maven uses its “nearest definition” strategy. This can silently select the wrong version, leading to resolution failures or runtime errors like ClassNotFoundException.
Analyze the Dependency Tree
Use mvn dependency:tree to see exactly what Maven resolved:
mvn dependency:tree -Dincludes=org.springframework:spring-coreThe -Dincludes filter shows only the dependency you care about. The output looks like:
[INFO] com.example:my-app:jar:1.0.0
[INFO] +- org.springframework:spring-webmvc:jar:6.1.4:compile
[INFO] | \- org.springframework:spring-core:jar:6.1.4:compile
[INFO] \- org.some.library:old-spring-lib:jar:1.0.0:compile
[INFO] \- org.springframework:spring-core:jar:5.3.30:compile (omitted for conflict)The (omitted for conflict) marker shows where Maven dropped a version.
Force a Specific Version
If Maven is picking the wrong version, explicitly declare the version you need in your pom.xml’s <dependencyManagement> section:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.1.4</version>
</dependency>
</dependencies>
</dependencyManagement>This forces all transitive references to use version 6.1.4, regardless of what individual dependencies request.
Exclude Conflicting Transitive Dependencies
Alternatively, exclude the problematic transitive dependency from the library that pulls it in:
<dependency>
<groupId>org.some.library</groupId>
<artifactId>old-spring-lib</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>This prevents the old version from being pulled in at all.
Fix 7: Resolve Parent POM Issues
If your project uses a parent POM that Maven cannot find, you get errors like:
[ERROR] Non-resolvable parent POM for com.example:my-module:1.0.0:
Could not find artifact com.example:parent-pom:pom:1.0.0Install the Parent POM Locally
If the parent POM is part of your project (a multi-module build), install it first:
cd parent-project
mvn clean install -NThe -N flag (non-recursive) installs only the parent POM without building child modules. Then go back to your module and build again.
Check relativePath
In a multi-module project, Maven looks for the parent POM relative to the child module. If the directory structure does not match the default (../pom.xml), specify the correct path:
<parent>
<groupId>com.example</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.0</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>If the parent is only available from a remote repository (not on the filesystem), set <relativePath/> to an empty value. This tells Maven to skip the local filesystem lookup and go straight to the repository:
<parent>
<groupId>com.example</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.0</version>
<relativePath/>
</parent>Fix 8: Check for Typos and Non-Existent Versions
This sounds basic, but it catches people more often than you would expect. A single wrong character in groupId, artifactId, or version causes a resolution failure.
Verify your dependency coordinates:
- Go to Maven Central Search or mvnrepository.com.
- Search for the artifact.
- Confirm the exact
groupId,artifactId, and available versions.
Watch for these common traps:
- Old group IDs: Some libraries changed their
groupIdover time. For example,javax.servletbecamejakarta.servletafter Jakarta EE took over. If you are using a newer version with the old group ID, it will not resolve. - Classifier issues: Some artifacts require a classifier like
jdk8orlinux-x86_64. Without the correct classifier, Maven cannot find the file. - Wrong packaging type: If you need a
pomtype (like a BOM) but left it as the defaultjar, resolution may fail.
Fix 9: Handle SNAPSHOT Resolution Failures
SNAPSHOT versions have special resolution rules. Maven checks for new SNAPSHOT versions periodically (configurable, defaults to daily). If the SNAPSHOT is not available or the repository does not allow snapshots, resolution fails.
Make sure the repository has snapshots enabled:
<repository>
<id>snapshots-repo</id>
<url>https://nexus.company.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>The <updatePolicy>always</updatePolicy> setting tells Maven to check for new snapshot versions on every build. Other options are daily (default), interval:X (minutes), and never.
Fix 10: Run Maven in Debug Mode
When none of the above fixes work, run Maven with the -X flag for full debug output:
mvn clean install -X 2>&1 | tee maven-debug.logThis produces a lot of output. Search for these key terms in the log:
- “Could not transfer”: Shows the exact URL Maven tried and the HTTP error code.
- “Authentication”: Reveals whether credentials were sent and accepted.
- “Using mirror”: Shows which mirror Maven is routing requests through.
- “Proxy”: Confirms whether proxy settings are active.
You can also use the Maven dependency plugin to get more insight:
mvn dependency:resolve -XThis focuses the debug output on dependency resolution specifically, cutting out most of the build noise.
For complex multi-module projects, the effective POM is also valuable:
mvn help:effective-pomThis shows the fully merged POM after all parent inheritance and profile activation. Check that repositories, mirrors, and dependency versions look correct in the output.
Fix 11: Check Java and Maven Version Compatibility
Certain dependency versions require specific Java versions. If you are running Java 8 but a dependency was compiled for Java 17, Maven may fail to read its descriptor.
Check your Java and Maven versions:
java -version
mvn --versionMake sure the Java version listed by mvn --version matches what you expect. Maven uses the JAVA_HOME environment variable. If JAVA_HOME points to a different JDK than what is on your PATH, you can get confusing errors.
If you are also running into memory issues during large builds, you may need to increase Maven’s heap size, which follows the same JVM tuning principles.
Fix 12: Verify Repository Accessibility
Sometimes the repository itself is down or unreachable. Test connectivity directly:
curl -I https://repo.maven.apache.org/maven2/You should get a 200 OK response. If you get a timeout, connection refused, or SSL error, the issue is network-level, not Maven-specific.
For internal repositories, check:
- Is the Nexus/Artifactory server running?
- Is the repository URL correct (check for trailing slashes, typos)?
- Have your credentials expired?
- Is the server’s SSL certificate valid and trusted by your JVM?
You can test artifact availability by constructing the direct URL. For org.springframework:spring-core:6.1.4, the URL is:
https://repo.maven.apache.org/maven2/org/springframework/spring-core/6.1.4/spring-core-6.1.4.pomOpen it in a browser. If you can see the POM XML, Maven Central has the artifact and the problem is on your end.
How Other JVM Build Tools Resolve Dependencies
Maven is not the only way to consume a Maven Central artifact. Gradle, sbt, Bazel, and Mill all read from the same registry, but their resolvers, lockfile strategies, and private-repo configurations differ enough that a fix that works for Maven may not transfer.
Maven (Apache Maven Resolver / Eclipse Aether). Uses a “nearest definition wins” algorithm: the version closest to the root of your dependency graph wins, with declaration order as the tiebreaker. There is no native lockfile. Reproducibility comes from <dependencyManagement> and BOMs. The Maven Resolver (formerly Aether) caches artifacts under ~/.m2/repository with per-artifact _remote.repositories metadata. Private repos go in settings.xml under <servers> and <mirrors>.
Gradle. Reads from Maven repositories but uses a completely different resolver. The default conflict resolution is “highest version wins” — the opposite of Maven. Gradle has true lockfiles via dependencyLocking (per-configuration gradle.lockfile files) and a strict resolution mode that fails the build on any version downgrade. Private repos go in repositories { maven { url ... credentials { ... } } } blocks inside build.gradle(.kts). The cache lives at ~/.gradle/caches/modules-2/, separate from Maven’s. Gradle also has variant-aware resolution (different artifacts per JVM target, OS, or feature), which Maven lacks entirely.
sbt. Uses Coursier as the resolver in modern versions (sbt 1.3+). Coursier is parallel by default, much faster than Maven Resolver. Conflicts resolve via “highest version wins” like Gradle, with eviction warnings printed during compile. Lock files arrive via the sbt-lock plugin or Coursier’s --mode=force-version flag — they are not built in. Private repos go in ~/.sbt/1.0/credentials.sbt and resolvers += "Internal" at "...". Coursier’s cache is at ~/.cache/coursier/v1/.
Bazel (rules_jvm_external). Does not use Maven-style transitive resolution at runtime. You declare a maven_install rule with a fully pinned list of artifacts and SHA-256 hashes. The maven_install.json file is the lockfile and must be committed. Adding a dependency requires running bazel run @unpinned_maven//:pin to regenerate the lock. Private repos go in the repositories parameter of maven_install. There is no ~/.m2-style local cache — Bazel’s content-addressed store is per-workspace.
Mill. Also uses Coursier under the hood, like sbt. Dependency declarations are inline Scala/Kotlin code. Lockfiles are opt-in via mill resolve __ | mill mill.modules.Util.lockFile. Private repos go in def repositoriesTask = T.task { super.repositoriesTask() ++ Seq(...) }. The cache shares Coursier’s ~/.cache/coursier.
The lockfile takeaway. Maven has no native lockfile. Gradle, Bazel, and sbt all support lockfiles, with different mechanisms. If reproducibility is critical and you cannot move off Maven, the closest equivalent is a strict BOM under <dependencyManagement> plus the maven-enforcer-plugin with the requireUpperBoundDeps rule.
The transitive-resolution takeaway. Maven’s “nearest wins” rule causes silent downgrades that no other tool produces. If a Maven build mysteriously picks an old transitive version, the same pom.xml in Gradle would pick the newer one. Running mvn dependency:tree (or gradle dependencies --configuration runtimeClasspath if you have a parallel Gradle build) often reveals the difference fastest.
Still Not Working?
If you have tried everything above and Maven still cannot resolve dependencies, check these less obvious causes:
- Maven wrapper version mismatch: If the project uses
mvnw, check.mvn/wrapper/maven-wrapper.properties. The wrapper may be downloading an old Maven version that has known bugs. Update it withmvn wrapper:wrapper -Dmaven=3.9.6. - OS-level DNS issues: Maven relies on DNS to resolve repository hostnames. Try
nslookup repo.maven.apache.orgto verify DNS resolution works. Corporate VPNs sometimes interfere with DNS. - Disk space: Maven cannot write downloaded artifacts if the disk is full. Check available space on the partition where
~/.m2/repositorylives. - File permissions: On Linux/macOS, check that your user owns the
~/.m2directory. Asudo mvn installin the past may have created files owned by root. Fix withsudo chown -R $(whoami) ~/.m2. - Antivirus or firewall interference: Some security software intercepts HTTPS connections and modifies certificates, causing SSL handshake failures. Try temporarily disabling your antivirus to test.
- Maven daemon (mvnd) cache: If you use
mvnd, it keeps a long-running daemon process that caches state. Restart it withmvnd --stopbefore retrying. - Gradle alternative: If you are migrating between build tools, dependency coordinates may differ. Check Gradle build failures for the Gradle-specific equivalent of these issues.
As a last resort, create a minimal pom.xml with just the failing dependency and try to build it in isolation. If it works, the problem is somewhere in your project’s dependency tree or settings inheritance. If it fails, the problem is environmental (network, proxy, JVM, or cache).
- Maven Central HTTPS-only enforcement. Since January 2020, Maven Central rejects plain HTTP requests. Any old
pom.xmlorsettings.xmlthat hardcodeshttp://repo1.maven.org/maven2returns 501. Update every URL tohttps://repo.maven.apache.org/maven2orhttps://repo1.maven.org/maven2. - Checksum verification failures behind transparent proxies. Some corporate proxies rewrite response bodies (for example, injecting a security banner into HTML pages they mistakenly serve as XML). Maven’s PGP and SHA checksum validation then rejects the artifact with a confusing “checksum validation failed” message. Disable checksum validation only as a diagnostic step (
mvn install -Cfor strict checksum,-cfor lax) and replace the proxy or whitelist the Maven Central host instead of leaving validation off. - Settings profile not activated. If the failing dependency lives behind a private repo configured inside a
<profile>insettings.xml, the profile must be active. Check withmvn help:active-profiles. Activate explicitly via-P profile-nameor add<activeByDefault>true</activeByDefault>to the profile’s<activation>block. - Toolchains misconfiguration. Projects that use
maven-toolchains-pluginto compile against a specific JDK can fail dependency resolution if the toolchain JDK has no internet access (some hardened JDK installs disable outbound HTTPS by default). The fix is usually to grant the toolchain JDK’scacertsthe same trust store as the system JDK.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Java Record Not Working — Compact Constructor Error, Serialization Fails, or Cannot Extend
How to fix Java record issues — compact constructor validation, custom accessor methods, Jackson serialization, inheritance restrictions, and when to use records vs regular classes.
Fix: OpenTelemetry Not Working — Traces Not Appearing, Spans Missing, or Exporter Connection Refused
How to fix OpenTelemetry issues — SDK initialization order, auto-instrumentation setup, OTLP exporter configuration, context propagation, and missing spans in Node.js, Python, and Java.
Fix: Spring Boot Test Not Working — ApplicationContext Fails to Load, MockMvc Returns 404, or @MockBean Not Injected
How to fix Spring Boot test issues — @SpringBootTest vs test slices, MockMvc setup, @MockBean vs @Mock, test context caching, and common test configuration mistakes.
Fix: Spring Boot @Cacheable Not Working — Cache Miss Every Time or Stale Data
How to fix Spring Boot @Cacheable issues — @EnableCaching missing, self-invocation bypass, key generation, TTL configuration, cache eviction, and Caffeine vs Redis setup.