You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow duplicate project names if they have distinct groups #281
nmcp throws an error if projects have the same name, for example if the root project is called :foo and there's a subproject :bar:foo.
A problem occurred configuring root project 'foo'.
> Nmcp: some projects have the same name: '${it.name}'. This creates issues when resolving the aggregation.
You can usually resolve this error by renaming your projects (including possibly your root project).
Or you can disable this check by calling `allowDuplicateProjectNames.set(true)`.
See https://github.com/gradle/gradle/issues/36167 for more details.
allowDuplicateProjectNames.set(true) disables the check - so I'm not blocked.
However, in my case the error is not valid. The two subprojects have distinct project.group values. A distinct group allows Gradle to differentiate the projects correctly.
// build.gradle.kts
group ="root"// foo/build.gradle.kts
group ="foo"
Can the warning be updated to check if the name and group of projects clash?
I think it's possible for nmcp to create a more refined check (check the resolved components from ResolvedComponentResult - if they are project dependencies then check to see if the expected project matches the actual).
But really it should be fixed in Gradle, so I made a PR: gradle/gradle#39241
I can also make a PR for the improved check in nmcp?
Thanks for raising this and offering to help. This is very kind but given that the workaround is pretty simple, I'd rather not add too much code for this.
Overall, I feel like the false positives raise awareness about the issue without being blocking so I'm enclined to keep them.
I've tweaked the error message a little bit there. Let me know if that works for you.
Thanks for raising this and offering to help. This is very kind but given that the workaround is pretty simple, I'd rather not add too much code for this.
Agree! The updated check is mostly finished, but I realised it was overkill for such a small check in nmcp.
For future reference, here's the check. Maybe it's useful elsewhere.
importorg.gradle.api.artifacts.component.ProjectComponentSelectorimportorg.gradle.api.artifacts.result.ResolvedComponentResultimportorg.gradle.api.artifacts.result.ResolvedDependencyResultimportorg.gradle.api.artifacts.result.UnresolvedDependencyResultimportorg.gradle.api.attributes.Usage/** * Fails if one of the aggregated projects was swallowed by dependency resolution. * * Gradle identifies the projects taking part in dependency resolution by their `group:name` coordinates. * If two projects share the same coordinates, Gradle cannot tell them apart: * - if both of them expose the `nmcp` variant, one is silently replaced by the other and its artifacts never make * it to the aggregation. * - else the dependency is unresolved and Gradle reports a confusing "no matching variant" error about a project * that was never requested. This happens when the aggregating project itself takes part in the conflict. * * [root] is the component of the aggregating project, i.e. the project applying `com.gradleup.nmcp.aggregation`. It * is not necessarily the root project of the build. * * This is a best effort check: it may miss conflicts. Set `allowDuplicateProjectNames` to `true` to disable it. * * See https://github.com/gradle/gradle/issues/36167 for more details.*/internalfuncheckProjectCoordConflict(
root:ResolvedComponentResult,
allowDuplicateProjectNames:Boolean,
lenient:Boolean,
) {
if (allowDuplicateProjectNames) {
return
}
root.dependencies.forEach { dependencyResult ->val requested = dependencyResult.requested as?ProjectComponentSelector?:return@forEach
when (dependencyResult) {
isResolvedDependencyResult-> {
val selected = dependencyResult.selected
if (!requested.matchesStrictly(selected.id)) {
duplicateProjectsError(
"project '${requested.projectPath}' was replaced by ${selected.id.displayName} during dependency resolution because they have the same group and name ('${selected.moduleVersion?.module}'). The artifacts of '${requested.projectPath}' are missing from the aggregation.",
)
}
}
isUnresolvedDependencyResult-> {
if (lenient) {
// If lenient, unresolved projects are expected. They are projects without `com.gradleup.nmcp`.return@forEach
}
// Gradle reports the missing `nmcp` variant on the component that actually took part in the// resolution.// - If it is [root], the requested project was collapsed into [root] by conflict// resolution and never resolved at all.// - If it is the requested project itself, that project simply does not apply `com.gradleup.nmcp`,// so let Gradle report it.if (!dependencyResult.missesTheNmcpVariantOn(root.id.displayName)) {
return@forEach
}
val rootModule = root.moduleVersion ?:return@forEach
duplicateProjectsError(
"project '${requested.projectPath}' could not be resolved because it has the same group and name as ${root.id.displayName} ('${rootModule.module}').",
)
}
}
}
}
/** * Whether variant selection failed on [componentDisplayName] for lack of an `nmcp` variant. * * The failure itself is always about the requested project ("Could not resolve project ':foo'.") and its cause names * the component that variant selection actually ran on ("No matching variant of project ':foo' was found."). * Those two differ when the requested project was collapsed into another component by conflict resolution. * * This matches Gradle error messages and may stop matching in a future Gradle version. If it does, the aggregation * fails with the Gradle error instead of ours.*/privatefun UnresolvedDependencyResult.missesTheNmcpVariantOn(componentDisplayName:String): Boolean {
val cause = failure.cause?.message.orEmpty()
return cause.contains("No matching variant of $componentDisplayName was found") &&
cause.contains("attribute '${Usage.USAGE_ATTRIBUTE.name}' with value '$usageValue'")
}
privatefunduplicateProjectsError(reason:String): Nothing {
error(
""" |Nmcp: $reason |You can usually resolve this error by renaming one of the projects (including possibly your root project) or by giving them distinct `group` values. |Or you can disable this check by calling `allowDuplicateProjectNames.set(true)`. |See https://github.com/gradle/gradle/issues/36167 for more details.""".trimMargin(),
)
}
Thanks again for the help! I'm going to close this one for now. Hopefully this can be handled on the Gradle side in the future. If this becomes too much of an issue, we can always revisit.
Activity
aSemy commentedon Sep 21, 2026
I think it's possible for nmcp to create a more refined check (check the resolved components from ResolvedComponentResult - if they are project dependencies then check to see if the expected project matches the actual).
But really it should be fixed in Gradle, so I made a PR: gradle/gradle#39241
I can also make a PR for the improved check in nmcp?
martinbonnin commentedon Sep 21, 2026
Thanks for raising this and offering to help. This is very kind but given that the workaround is pretty simple, I'd rather not add too much code for this.
Overall, I feel like the false positives raise awareness about the issue without being blocking so I'm enclined to keep them.
I've tweaked the error message a little bit there. Let me know if that works for you.
aSemy commentedon Sep 21, 2026
Agree! The updated check is mostly finished, but I realised it was overkill for such a small check in nmcp.
For future reference, here's the check. Maybe it's useful elsewhere.
martinbonnin commentedon Sep 21, 2026
Thanks again for the help! I'm going to close this one for now. Hopefully this can be handled on the Gradle side in the future. If this becomes too much of an issue, we can always revisit.