Repository: GradleUp/shadow (kotlin)

Issue:
StackOverflowError when using a dependency filter with minimize in 9.0.0
### Expected and Results

Seeing the following stack overflow when using minimize with a dependency exclusion:

```
FAILURE: Build failed with an exception.

* What went wrong:
java.lang.StackOverflowError (no error message)

* Try:
> Run with --info or --debug option to get more log output.
> Get more help at https://help.gradle.org.

* Exception is:
java.lang.StackOverflowError
        at kotlin.text.Regex.<init>(Regex.kt:88)
        at com.github.jengelman.gradle.plugins.shadow.tasks.DependencyFilter$AbstractDependencyFilter.toSpec$lambda$5(DependencyFilter.kt:108)
        at com.github.jengelman.gradle.plugins.shadow.tasks.DependencyFilter$AbstractDependencyFilter.isIncluded(DependencyFilter.kt:102)
        at com.github.jengelman.gradle.plugins.shadow.internal.MinimizeDependencyFilter.resolve(MinimizeDependencyFilter.kt:16)
        at com.github.jengelman.gradle.plugins.shadow.internal.MinimizeDependencyFilter.resolve(MinimizeDependencyFilter.kt:21)
        at com.github.jengelman.gradle.plugins.shadow.internal.MinimizeDependencyFilter.resolve(MinimizeDependencyFilter.kt:21)
        ...
```

### Related environment and versions

Gradle 8.14.3, Shadow 9.0.0

### Reproduction steps

Here is the basic structure for how the shadow plugin is configured
```
tasks.shadowJar {
    dependencies { exclude(dependency("org.slf4j:slf4j-api")) }

    exclude("META-INF/maven/**/*")

    minimize {
        exclude(dependency("com.fasterxml.jackson.core:jackson-databind:.*"))
    }

    relocate("com.foo", "shadow.com.foo")

    mergeServiceFiles()
}
```

### Anything else?

_No response_

Pull request description:
- Closes #1610.
- Fixes https://github.com/GradleUp/shadow/pull/1021#discussion_r2262468388.

---

- [x] [CHANGELOG](https://github.com/GradleUp/shadow/blob/main/docs/changes/README.md)'s "Unreleased" section has been updated, if applicable.

Patch:
diff --git a/docs/changes/README.md b/docs/changes/README.md
index 480238770..ffdbb8106 100644
--- a/docs/changes/README.md
+++ b/docs/changes/README.md
@@ -14,6 +14,7 @@
 ### Fixed
 
 - Fix the regression of can't shadow directory inputs. ([#1606](https://github.com/GradleUp/shadow/pull/1606))
+- Fix the regression of `MinimizeDependencyFilter`. ([#1611](https://github.com/GradleUp/shadow/pull/1611))
 
 ## [9.0.0](https://github.com/GradleUp/shadow/compare/9.0.0) - 2025-08-07
 
diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt
index 506ef562e..a38ac71f0 100644
--- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt
+++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeDependencyFilter.kt
@@ -13,12 +13,14 @@ internal class MinimizeDependencyFilter(
     excludedDependencies: MutableSet<ResolvedDependency>,
   ) {
     dependencies.forEach {
-      if (it.isIncluded() && !isParentExcluded(excludedDependencies, it)) {
+      val added = if (it.isIncluded() && !isParentExcluded(excludedDependencies, it)) {
         includedDependencies.add(it)
       } else {
         excludedDependencies.add(it)
       }
-      resolve(it.children, includedDependencies, excludedDependencies)
+      if (added) {
+        resolve(it.children, includedDependencies, excludedDependencies)
+      }
     }
   }
 


Test patch:
diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt
index fbdc57f51..4bbb9456c 100644
--- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt
+++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt
@@ -2,6 +2,7 @@ package com.github.jengelman.gradle.plugins.shadow
 
 import assertk.assertThat
 import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.SHADOW_JAR_TASK_NAME
+import com.github.jengelman.gradle.plugins.shadow.util.Issue
 import com.github.jengelman.gradle.plugins.shadow.util.containsAtLeast
 import com.github.jengelman.gradle.plugins.shadow.util.containsNone
 import com.github.jengelman.gradle.plugins.shadow.util.containsOnly
@@ -213,6 +214,38 @@ class MinimizeTest : BasePluginTest() {
     }
   }
 
+  @Issue(
+    "https://github.com/GradleUp/shadow/issues/1610",
+  )
+  @Test
+  fun excludeCircularDependencies() {
+    publishArtifactCD(circular = true)
+
+    val dependency = "'my:d:1.0'"
+    projectScript.appendText(
+      """
+        dependencies {
+          implementation $dependency
+        }
+        $shadowJarTask {
+          minimize {
+            exclude(dependency($dependency))
+          }
+        }
+      """.trimIndent(),
+    )
+
+    run(shadowJarPath)
+
+    assertThat(outputShadowedJar).useAll {
+      containsOnly(
+        "c.properties",
+        "d.properties",
+        *manifestEntries,
+      )
+    }
+  }
+
   @ParameterizedTest
   @ValueSource(booleans = [false, true])
   fun enableMinimizationByCliOption(enable: Boolean) {