openrewrite / openrewrite/rewrite

UpgradeDependencyVersion bumps a shared version property to a version its siblings never published

Open
#8,656 2 comments 0 reactions 1 assignee View on GitHub

@MBoegers is already working on this.

Since Aug 31, 2026.

bug maven
Dominant language
Java
Stars
3.7k
Forks
571
Avg merge
13h 12m
Merged PRs (30d)
261

Description

Problem

org.openrewrite.maven.UpgradeDependencyVersion writes a resolved version into a shared <properties> entry without checking that the version exists for the other artifacts that resolve through that property. Every sibling reading the property is left pointing at a version that was never published, so the POM stops resolving.

Evidence in the wild

Reported from a Moderne flagship run on ALL/Open Source/FINOS ("Spring Boot 4.0 best practices"): 102 error markers across 7 sibling artifacts, all one root cause, concentrated in finos/legend-depot, finos/legend-sdlc and finos/legend-shared.

artifact markers
jackson-core 45
jackson-dataformat-yaml 18
jackson-jaxrs-json-provider 11
jackson-datatype-jsr310 7
jackson-datatype-jdk8 7
jackson-module-afterburner 7
jackson-datatype-joda 7

All markers read Unable to download POM: com.fasterxml.jackson.core:jackson-core:2.21 and similar.

finos/legend-depot/pom.xml shows why that artifact list is exactly those 7: ${jackson.version} is shared by all of them plus jackson-annotations, while jackson-databind sits on a separate ${jackson.databind.version} — which is precisely why jackson-databind is absent from the marker list.

[!NOTE]
FINOS's Spring Boot 4.0 run has since been killed by the 20-minute watchdog (20260825034241-jGivl on 2026-08-25, 20260826034706-I9wIb on 2026-08-26), producing zero results. A recent run showing ~4 markers is not evidence this is fixed — re-run the org, or work from the 2026-08-20 data.

Why 2.21

Since 2.20, com.fasterxml.jackson.core:jackson-annotations publishes bare minor versions, while every other Jackson 2.x artifact publishes three-part versions:

jackson-annotations   … 2.19.3  2.19.4  2.20-rc1  2.20  2.21  2.22
jackson-core          … 2.19.3  2.19.4  2.20.0  2.20.1  2.20.2  2.21.0 … 2.21.6

So 2.21 is a real released version of jackson-annotations and of nothing else.

The trigger is rewrite-jackson's UpgradeJackson_2_3_Dependencies (jackson-2-3.yml), which pins that version deliberately — Jackson 3 still consumes the com.fasterxml.jackson.annotation annotations:

- org.openrewrite.java.dependencies.UpgradeDependencyVersion:
    groupId: com.fasterxml.jackson.core
    artifactId: jackson-annotations
    newVersion: "2.21"
    overrideManagedVersion: true

It is reached from Spring Boot 4.0 via spring-framework-70.ymlorg.openrewrite.java.jackson.UpgradeJackson_2_3. The recipe is not at fault — any exact version that only one consumer of a shared property publishes reproduces this.

Reproduction

UpgradeDependencyVersion("com.fasterxml.jackson.core", "jackson-annotations", "2.21", null, true, null) against:

<project>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1</version>
    <properties>
        <jackson.version>2.19.0</jackson.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson.version}</version>
        </dependency>
    </dependencies>
</project>

Today the property becomes <jackson.version>2.21</jackson.version>, and jackson-core:2.21 does not exist. Reproduces equally through dependencyManagement, through a property declared in a local parent with consumers in sibling modules, and through plugin <dependencies> / <annotationProcessorPaths>.

Desired behaviour

Decouple the targeted dependency: write an explicit <version> on the dependency (or its dependencyManagement entry) and leave the property alone.

rewrite-gradle already behaves this way — UpgradeDependencyVersion#safeUpdatedVersion requires the agreed version to be published for every untargeted neighbour sharing the variable, and UpgradeDependencyVersionTest#doesNotCorruptSharedGradleProperty asserts exactly this outcome on the same Jackson 2.21 case. The alternatives considered — skip with a Markup.warn, or only update when all consumers agree on a common version — leave the requested upgrade undone and would leave Maven and Gradle behaving differently on identical input.

Single-consumer property updates should be unchanged.

Starting point

  • There is a working implementation on branch tim/taipei-v2 (from now-closed PR #8460). It is +160/−28 in UpgradeDependencyVersion plus 6 tests, and funnels every <version> write through one seam so plugin dependencies and annotation processor paths are covered too.

Verified against main on 2026-08-26:

  • merges clean;
  • all 6 new shared-property tests pass;
  • UpgradeDependencyVersionTest shows no regressions — the only failures (deriveFromNexus, deriveFromNexusUpgrade, badManagedVersion) fail identically on unmodified main in the same environment;
  • on the real finos/legend-depot dependencyManagement block it leaves ${jackson.version} at 2.10.5 and decouples jackson-annotations to an explicit <version>2.21</version>, which would clear all 102 markers.

Known limitation to resolve before merging: the existence check treats metadata that cannot be downloaded as evidence that the version does exist, so a network-degraded run silently falls back to today's broken behaviour. That is the safer default for not blocking legitimate upgrades, but it deserves a deliberate decision and a comment.

Follow-up, not required here: the pinned 2.21 in rewrite-jackson will go stale (2.22 is already published); 2.x may be preferable once this lands.

Whoever picks this up is welcome to take the branch as-is or start over — it is not reserved.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.