You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "gnodet (via GitHub)" <gi...@apache.org> on 2026/06/18 05:18:31 UTC

[I] StackOverflowError in DefaultModelBuilder.readFileModel with recursive parent resolution [maven]

gnodet opened a new issue, #12301:
URL: https://github.com/apache/maven/issues/12301

   ## Description
   
   Building `jackrabbit-filevault` with Maven from the `maven-4.0.x` branch causes a `StackOverflowError` in `DefaultModelBuilder$ModelBuilderSessionState.readFileModel`.
   
   The stack shows infinite recursion through this cycle:
   ```
   readFileModel → getEnhancedProperties → doReadFileModel → cache → readFileModel
   ```
   
   ## Stack trace (tail)
   
   ```
   at org.apache.maven.impl.model.DefaultModelBuilder$ModelBuilderSessionState.cache(DefaultModelBuilder.java:2140)
   at org.apache.maven.impl.model.DefaultModelBuilder$ModelBuilderSessionState.readFileModel(DefaultModelBuilder.java:1484)
   at org.apache.maven.impl.model.DefaultModelBuilder$ModelBuilderSessionState.getEnhancedProperties(DefaultModelBuilder.java:705)
   at org.apache.maven.impl.model.DefaultModelBuilder$ModelBuilderSessionState.doReadFileModel(DefaultModelBuilder.java:1653)
   at org.apache.maven.impl.model.DefaultModelBuilder$ModelBuilderSessionState.lambda\$cache\$14(DefaultModelBuilder.java:2140)
   at org.apache.maven.impl.cache.AbstractRequestCache.request(AbstractRequestCache.java:69)
   ... (repeating)
   ```
   
   ## Reproducer
   
   ```bash
   git clone https://github.com/apache/jackrabbit-filevault.git
   cd jackrabbit-filevault
   mvn -B -e clean package -DskipTests
   ```
   
   Build fails in ~5s with StackOverflowError during POM resolution, never reaching compilation.
   
   ## Environment
   
   - Maven: built from `maven-4.0.x` branch (bootstrapped with 4.0.0-rc-5)
   - JDK: 17 (Temurin)
   - OS: Ubuntu (GitHub Actions runner)
   
   ## Context
   
   Found during [Maven 4 compatibility testing](https://github.com/gnodet/maven4-testing/issues/20577) of Apache projects.
   
   _Claude Code on behalf of Guillaume Nodet_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] StackOverflowError in DefaultModelBuilder.readFileModel with recursive parent resolution [maven]

Posted by "gnodet (via GitHub)" <gi...@apache.org>.
gnodet commented on issue #12301:
URL: https://github.com/apache/maven/issues/12301#issuecomment-4738551206

   ## Root Cause Analysis
   
   ### The Project Pattern That Triggers This
   
   Jackrabbit FileVault uses an **internal parent** anti-pattern in combination with CI-friendly versions:
   
   - The **root POM** (`pom.xml`) declares `<parent>` pointing to `parent/pom.xml` (a reactor module in the same repo)
   - The parent reference uses a **CI-friendly version**: `<version>${revision}</version>`
   - `.mvn/` lives at the repo root, so `session.getRootDirectory()` = the directory of `pom.xml`
   
   ### The Exact Recursion Cycle
   
   The cycle involves **two interacting feedback loops** exposed by how `CyclicCacheAccessException` is handled.
   
   **Step-by-step trace** (all on one thread):
   
   1. `loadFilePom` calls `readFileModel(rootPOM)` → `cache(rootPOM, FILE, doReadFileModel)` — cache miss, starts computing, `CachingSupplier` marks `computingThread = currentThread`
   
   2. Inside `doReadFileModel(rootPOM)` (line ~1579–1601):  
      The parent version `${revision}` sets `versionContainsExpression = true`, so it resolves the parent path and calls:  
      `derive(parent/pom.xml).readFileModel()` → `cache(parent/pom.xml, FILE, doReadFileModel)` — new cache entry, starts computing
   
   3. Inside `doReadFileModel(parent/pom.xml)` (line 1653):  
      `getEnhancedProperties(parentModel, rootDirectory)` is called.  
      Since `parent/pom.xml` is not the root (`/filevault/parent/` ≠ `/filevault/`), it takes the non-root branch (line 703–706):  
      ```java
      Model rootModel = derive(Sources.buildSource(rootModelPath)).readFileModel();
      //                                                    ↑ rootModelPath = /filevault/pom.xml
      ```
   
   4. `readFileModel(rootPOM)` → `cache(rootPOM, FILE, ...)` — **same key as step 1!**  
      `CachingSupplier` detects re-entrancy: `value == null && computingThread == currentThread` → throws `CyclicCacheAccessException`
   
   5. **`AbstractRequestCache.request()` catches `CyclicCacheAccessException` and calls `supplier.apply(req)` directly** (line 69), bypassing the cache. This re-invokes `doReadFileModel(rootPOM)` without any guard.
   
   6. `doReadFileModel(rootPOM)` again (step 2 repeats): parent version has `${revision}` → tries to read `parent/pom.xml` → `cache(parent/pom.xml, FILE, ...)` — **same key as step 3!**  
      `CyclicCacheAccessException` again → `doReadFileModel(parent/pom.xml)` called directly
   
   7. `doReadFileModel(parent/pom.xml)` again (step 3 repeats): `getEnhancedProperties` → `readFileModel(rootPOM)` → step 4 repeats → step 5 repeats → step 6...
   
   **Steps 5→6→7→5→6→7→...** until `StackOverflowError`.
   
   ### Why the `CyclicCacheAccessException` Fallback Makes It Worse
   
   `AbstractRequestCache.request()` catches `CyclicCacheAccessException` and falls back to calling the supplier directly. The comment says this is to handle batch/singular re-entrant access. But in this context it is the wrong escape hatch: calling `supplier.apply(req)` on `doReadFileModel` doesn't terminate — it just re-enters the same computation that caused the exception, starting the whole cycle over with one more frame on the stack.
   
   ### Two Interacting Root Causes
   
   1. **`getEnhancedProperties` reads the root model via `readFileModel`** (line 705), which triggers the full `doReadFileModel` pipeline including another call to `getEnhancedProperties`. For a non-root module whose parent IS the root POM, this creates a circular read dependency: `doReadFileModel(parent/) → getEnhancedProperties → readFileModel(root) → doReadFileModel(root) → readFileModel(parent/) → ...`
   
   2. **`doReadFileModel` reads the parent POM to resolve CI-friendly version coordinates** (line 1601, when `versionContainsExpression`), which for the root POM triggers reading the internal parent module. Combined with (1), these two loops interlock into an unbounded cycle.
   
   ### Suggested Fix
   
   The cleanest fix is to make `getEnhancedProperties` perform a **lightweight property-only read** of the root model rather than calling the full `readFileModel()` pipeline:
   
   ```java
   // In getEnhancedProperties(), instead of:
   Model rootModel = derive(Sources.buildSource(rootModelPath)).readFileModel();
   
   // Use a lightweight read that extracts only properties (no parent resolution, no getEnhancedProperties call):
   Model rootModel = derive(Sources.buildSource(rootModelPath)).readRawXmlPropertiesOnly();
   ```
   
   Alternatively, add a depth guard / in-progress set to `getEnhancedProperties` so that if it is already being executed for a given source path on the current call chain it returns early (skipping the recursive root model read). A thread-local `Set<Path>` of "currently resolving" paths in `getEnhancedProperties` would suffice.
   
   The `CyclicCacheAccessException` fallback itself might also need to be re-examined: re-running the full supplier without a guard means any cycle that goes through that path will stack-overflow rather than produce a meaningful error.
   
   ---
   
   *Analyzed from the Maven source at `impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java` and `impl/maven-impl/src/main/java/org/apache/maven/impl/cache/AbstractRequestCache.java`. The critical methods are `doReadFileModel` (lines 1491–1705), `getEnhancedProperties` (lines 676–714), and `AbstractRequestCache.request` (lines 61–71).*


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] StackOverflowError in DefaultModelBuilder.readFileModel with recursive parent resolution [maven]

Posted by "gnodet (via GitHub)" <gi...@apache.org>.
gnodet closed issue #12301: StackOverflowError in DefaultModelBuilder.readFileModel with recursive parent resolution
URL: https://github.com/apache/maven/issues/12301


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org