Skip to content

Maven pom rewrites add a second <repositories> or <dependencyManagement> section when the existing one is self-closed or has a comment before <dependencies>, so Maven refuses the pom #342

Description

[agent] Found by the scheduled Maven bug-hunt routine (ledger #318).

Summary

The hosted rewriter (scan --mode hosted) and the vendored wiring (vendor) each look for an existing section by an exact text pattern. When that pattern doesn't match, they write a brand-new section before </project>, even though the pom already has one. Maven's pom reader rejects the result with Non-parseable POM … Duplicated tag, so nothing builds. Meanwhile socket-patch exits 0, reports redirected: 1 / applied: 1 with no warning, and vex attests not_affected.

Three ordinary pom shapes trigger it:

shape mode why the anchor is missed result
<repositories/> (self-closed, empty) hosted insert_maven_repository checks pom.contains("<repositories>") a second <repositories> before </project>
<repositories/> vendored build_repo_edit anchors on </repositories> a second <repositories>
<dependencyManagement> with an XML comment before <dependencies> (e.g. <!-- versions shared across the org -->), and the patched GA is transitive hosted the regex (?s)<dependencyManagement>\s*<dependencies> allows only whitespace between the tags a second <dependencyManagement>
<dependencyManagement/>, patched GA transitive hosted same regex a second <dependencyManagement>

This is a different mechanism from #259, where edits land inside comments or profiles. Here the anchor is missed entirely and a duplicate top-level element is created. Masking comments, as #259 suggests, would not fix the self-closed shapes, and would only fix the comment shape if the regex is also changed.

Impact

  • The build is broken on every Maven line (3.6.3 → 4.0.0-rc-7) right after a successful scan / vendor.
  • The CLI's JSON and vex both claim the patch is in effect: vex --no-verify emits not_affected for the hosted case, and vex --offline does the same for the vendored case.

Repro

Setup: socket-patch 4.0.0 built from main f6b7fb9, and real Apache Maven. For hosted, a local stub API serves the same grant, patched jar and served pom as crates/socket-patch-cli/tests/e2e_redirect_maven_build.rs (commons-text 1.10.0 → 1.10.0-socket.4d5e6f70), and a settings.xml mirror maps socket-patch-<uuid> onto the stub. For vendored, a hand-staged .socket/manifest.json + blob is used, as in e2e_vendor_maven_build.rs.

Hosted, comment inside <dependencyManagement> (commons-text arrives transitively via commons-configuration2 2.9.0):

<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId><artifactId>app</artifactId><version>1.0.0</version>
  <dependencyManagement>
    <!-- versions shared across the org -->
    <dependencies>
      <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency><groupId>org.apache.commons</groupId><artifactId>commons-configuration2</artifactId><version>2.9.0</version></dependency>
  </dependencies>
</project>
$ socket-patch scan --mode hosted --json --yes --cwd . --api-url http://127.0.0.1:8765 --org test-org --api-token fake
exit 0, redirect.redirected = 1, warnings: [redirect_maven_dep_management_added]
# pom.xml now has a SECOND <dependencyManagement> (holding commons-text 1.10.0-socket.4d5e6f70) after </dependencies>

$ socket-patch vex --no-verify --product pkg:maven/com.example/app@1.0.0 -O vex.json ...
exit 0, not_affected for pkg:maven/org.apache.commons/commons-text@1.10.0

$ mvn -B -s settings.xml org.apache.maven.plugins:maven-dependency-plugin:3.1.2:copy-dependencies
[ERROR] Non-parseable POM /…/pom.xml: Duplicated tag: 'dependencyManagement' (position: START_TAG seen ...</dependencies>\n  <dependencyManagement>... @21:25)
exit 1

Self-closed repositories, hosted or vendored (a direct commons-text:1.10.0 dependency):

<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId><artifactId>app</artifactId><version>1.0.0</version>
  <repositories/>
  <dependencies>
    <dependency><groupId>org.apache.commons</groupId><artifactId>commons-text</artifactId><version>1.10.0</version></dependency>
  </dependencies>
</project>
$ socket-patch scan --mode hosted ...     # or: socket-patch vendor --json --offline
exit 0, redirected = 1 (applied = 1), no warnings
$ mvn ... copy-dependencies
[ERROR] Non-parseable POM /…/pom.xml: Duplicated tag: 'repositories' (position: START_TAG seen ...</dependencies>\n  <repositories>... @12:17)

Control: the same poms without the self-closed tag or the comment are rewritten in place and resolve the patched jar (PATCHED commons-text-1.10.0-socket.4d5e6f70.jar, and for vendored PATCHED commons-text-1.10.0.jar).

Expected vs actual

  • Expected: the rewrite leaves a pom Maven can read. CLI_CONTRACT.md / docs/ecosystems.md describe hosted Maven as "fail-closed" by pinning the suffixed version, and vendored as a committed file:// repository wired into the project pom. If the tool can't find a safe anchor, it should expand the self-closed element, or refuse with a warning instead of reporting redirected / applied.
  • Actual: a duplicate top-level element, exit 0, a positive VEX, and a build Maven won't load.

Matrix (Linux, JDK 21; each cell run twice on fresh copies)

case Maven 3.6.3 3.8.8 3.9.11 4.0.0-rc-7
hosted, <repositories/> Duplicated tag Duplicated tag Duplicated tag Duplicated tag
hosted, comment in <dependencyManagement> Duplicated tag Duplicated tag Duplicated tag Duplicated tag
hosted, <dependencyManagement/> Duplicated tag Duplicated tag Duplicated tag Duplicated tag
vendored, <repositories/> Duplicated tag Duplicated tag Duplicated tag Duplicated tag
controls (hosted direct / transitive, vendored plain) — — PATCHED PATCHED

macOS and Windows weren't probed. The rewrite is pure text, so it doesn't depend on the OS.

Suspect code (main f6b7fb9)

  • crates/socket-patch-core/src/patch/redirect/mod.rs:7007: insert_maven_repository uses pom.contains("<repositories>"), else a new section before </project> (line 7011).
  • crates/socket-patch-core/src/patch/redirect/mod.rs:7028: the insert_maven_dependency_management regex (?s)<dependencyManagement>\s*<dependencies>, else a new section (line 7037).
  • crates/socket-patch-core/src/vendor/maven_repo.rs:1115: build_repo_edit anchors only on </repositories>, then falls back to a new section before </project> (line 1117).

Related, but a different mechanism: #259 (edits landing in comments/profiles/plugins) and #260 (redirect confirmed by substring, which is why vex accepts these poms).

Activity

  1. mikolalysenko commented on Sep 30, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged: priority:p3 (Maven). Not a duplicate: as the report says, this is a missed anchor that creates a duplicate top-level element, not an edit that lands inside a comment or profile (#259). No open or merged PR fixes it. The suspect sites (insert_maven_repository with pom.contains("<repositories>"), the <dependencyManagement>\s*<dependencies> regex, and maven_repo.rs build_repo_edit anchoring on </repositories>) are all ad-hoc text anchors on the pom. A structure-aware pom editor shared by the hosted and vendored paths would fix this together with #259, so the two should be looked at together when the Maven work is picked up.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-triage (Maven bug-hunt, ledger #318): the hosted case still reproduces on main 2463257 (the v5 consolidation, #277).

    I ran the e2e_redirect_maven_build capstone's real writer with the consumer pom's only change being a self-closed <repositories/> before </project>. scan --mode hosted --json exits 0 with redirect.redirected: 1 and vex.statements: 1, and the rewritten pom has a second <repositories>:

    • Maven 3.9.11 (2 of 2 runs): mvn -o validate → [FATAL] Non-parseable POM …/pom.xml: Duplicated tag: 'repositories' (position: START_TAG seen ...<repositories/>\n <repositories>... @16:17)
    • Maven 4.0.0-rc-7: Non-parseable POM …: Unable to read model: Duplicated tag: 'repositories'

    I didn't re-check the vendored side this run. v5 routes reactors through a new backend (vendor/jvm/maven_reactor.rs), and single-POM projects still use maven_repo.rs.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 3, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Architecture audit (ecosystems and formats): the hosted rows here come from insert_maven_repository / insert_maven_dependency_management anchoring on exact text. #717 locates those anchors through the shared formats::maven scanner, self-closed forms included. The vendored row (build_repo_edit) is the next checklist item of the tracking issue #715.


    Generated by Claude Code

  4. added
    v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.
    compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.
    and removed on Oct 9, 2026
  5. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    v5 release blocker (P1). Ordinary self-closing/commented Maven XML must not acquire duplicate repositories/dependencyManagement sections after a first patch.

    This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.

  6. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming for v5 blocker burn-down (shared root cause: hosted Maven pom rewriter locates // with raw text anchors instead of the scope-aware formats::maven scanner). Branch: agent/v5-maven-pom-scope. Claim-ID: 20261009T164149Z-a78ef2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:claimedagent:triagedbugSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentcompatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.pm:mavenMavenpriority:p1v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions