gradle/gradle · error · InvalidUserCodeException

Both dependency locking and fail on dynamic versions are ena

Error message

Both dependency locking and fail on dynamic versions are enabled. You must choose between the two modes.

What it means

ResolutionExecutor.getAllVersionLocks builds the lock set for a resolve. Dependency locking already pins every module, so the resolutionStrategy.failOnDynamicVersions() mode (also switched on by failOnNonReproducibleResolution()), whose job is to error out when dynamic versions are used, is mutually exclusive with it. When both are active Gradle fails fast with this InvalidUserCodeException instead of resolving with contradictory semantics.

Source

Thrown at platforms/software/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ResolutionExecutor.java:476

            repositories,
            params.getComponentMetadataRules(),
            params.getVariantDerivationStrategy(),
            legacyParams.getComponentSelectionRules(),
            params.isDependencyVerificationEnabled(),
            params.getCacheExpirationControl(),
            params.getRootComponent().getMetadata().getAttributesSchema()
        ));

        return new ComponentResolversChain(resolvers);
    }

    private ImmutableList<ResolutionParameters.ModuleVersionLock> getAllVersionLocks(ResolutionParameters params) {
        if (!params.isDependencyLockingEnabled()) {
            return params.getModuleVersionLocks();
        }

        if (params.isFailingOnDynamicVersions()) {
            throw new InvalidUserCodeException(
                "Both dependency locking and fail on dynamic versions are enabled. You must choose between the two modes."
            );
        } else if (params.isFailingOnChangingVersions()) {
            throw new InvalidUserCodeException(
                "Both dependency locking and fail on changing versions are enabled. You must choose between the two modes."
            );
        }

        return ImmutableList.<ResolutionParameters.ModuleVersionLock>builder()
            .addAll(getLockfileLocks(params))
            .addAll(params.getModuleVersionLocks())
            .build();
    }

    private ImmutableList<ResolutionParameters.ModuleVersionLock> getLockfileLocks(ResolutionParameters params) {
        DependencyLockingState dependencyLockingState = dependencyLockingProvider.loadLockState(
            params.getDependencyLockingId(),
            params.getResolutionHost().displayName()

View on GitHub (pinned to 534f27719b)

Solutions

  1. Remove failOnDynamicVersions()/failOnNonReproducibleResolution() from configurations that use dependency locking; the lockfile enforces reproducibility
  2. Keep the two modes on disjoint configurations if both are genuinely needed
  3. Audit convention plugins for global resolutionStrategy settings before turning on locking

Example fix

// before
configurations {
    compileClasspath {
        resolutionStrategy.failOnNonReproducibleResolution()
        dependencyLocking { lockThisAndSubConfigurations() }
    }
}
// after
configurations {
    compileClasspath {
        dependencyLocking { lockThisAndSubConfigurations() }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Convention-plugin guard: do not enable fail-on-dynamic where lockfiles exist
allprojects {
    afterEvaluate {
        def hasLock = file('gradle.lockfile').exists()
        if (hasLock) {
            configurations.matching { it.resolutionStrategy }.all { c ->
                // nothing to enforce directly; keep conventions from setting the flag
            }
        }
    }
}
// Prefer: only set failOnDynamicVersions when locking is NOT configured
if (!project.file('gradle.lockfile').exists()) {
    configurations.all { resolutionStrategy.failOnNonReproducibleResolution() }
}

Prevention

When it happens

Trigger: A configuration has dependency locking active (dependencyLocking { lockThisAndSubConfigurations() } / activateDependencyLocking(), or a gradle.lockfile exists) while the same configuration's resolutionStrategy calls failOnDynamicVersions() or failOnNonReproducibleResolution().

Common situations: Teams adopting dependency locking on builds that already guarded reproducibility with failOnNonReproducibleResolution(); platform conventions applied globally colliding with per-project locking; CI enabling locking while a convention plugin sets failOnDynamicVersions for release checks.

Related errors


AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22). Data as JSON: /api/errors/6dbbc51c9b0c55c7. Report an issue: GitHub.