Using a BuildService (or something similar) inside of a ValueSource

I am using a ValueSource that communicates with an API as part of it’s obtain implementation. I have a BuildService which I use to maintain a single authenticated client session for this API, since I use this API throughout my build. The BuildService is successfully used in multiple tasks even if configuration caching is enabled.

For a task, I have:

  abstract class TaskThatUsesGit: DefaultTask() {
    @get:Internal val ghProvider = project.gradle.gitBuildService()
  }

I tried to do something similar for my ValueSource with the following:

interface GitHubAPIValueSourceProvider: ValueSourceParameters {
  var ghAPIProvider: Provider<GitBuildService>
}



abstract class ValueSourceThatUsesGit: ValueSource<String, GitHubAPIValueSourceProvider> {


  override fun obtain(): String {
	val buildService = parameters.ghAPIProvider.orNull ?: err("ghAPIProvider provided a null")
	  ...
  }


}

This led to the error:

org.gradle.api.GradleException: Could not load the value of field `__ghAPIProvider__

I am probably not doing this corectly. All that I want is for my ValueSource to use the same object as that is in the BuildService, I do not want to re-initialize this object more than once during a single build, including during the configuration phase and when obtaining values from ValueSource

ghAPIProvider should probably be val, not var.
I remember that if you use var where val should be used, you can get some strange problems.
Not sure whether it will help in your case, but worth a try.

Sorry for the late reply.

If ghAPIProvider it a val, it no longer is settable.

Here is how I use the value source. As you can see, the code will not compile if ghAPIProvider is a val.

project.providers.of(ValueSourceThatUsesGit::class.java) {
  it.parameters.ghAPIProvider = project.gradle.gitBuildService()
}

As an experiment, I tried making ghAPIProvider a val but then also made it a Property so that I can use the property’s set method:

project.providers.of(ValueSourceThatUsesGit::class.java) {
  it.parameters.ghAPIProvider.set(project.gradle.gitBuildService())
}

This did not work. I got the same error as in my original post:

org.gradle.api.GradleException: Could not load the value of field `__ghAPIProvider__
org.gradle.api.GradleException: Could not load the value of field `__ghAPIProvider__` of `matt.mbuild.admin.valuesource.GitHubAPIValueSourceProvider` bean found in field `parameters` of `org.gradle.api.internal.provider.DefaultValueSourceProviderFactory$DefaultObtainedValue` bean found in field `obtainedValue` of `org.gradle.configurationcache.fingerprint.ConfigurationCacheFingerprint$ValueSource` bean found in Gradle runtime.
	at org.gradle.configurationcache.serialization.beans.BeanPropertyReaderKt.readPropertyValue(BeanPropertyReader.kt:108)
	at org.gradle.configurationcache.serialization.beans.BeanPropertyReader.readStateOf(BeanPropertyReader.kt:67)
	at org.gradle.configurationcache.serialization.codecs.BeanCodec.readBeanOf(BeanCodec.kt:72)
	at org.gradle.configurationcache.serialization.codecs.BeanCodec.decode(BeanCodec.kt:47)
	at org.gradle.configurationcache.serialization.CombinatorsKt$reentrant$1$decodeLoop$1.invokeSuspend(Combinators.kt:165)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115)
	at org.gradle.configurationcache.serialization.CombinatorsKt$reentrant$1.decodeLoop(Combinators.kt:166)
	at org.gradle.configurationcache.serialization.CombinatorsKt$reentrant$1.decode(Combinators.kt:130)
	at org.gradle.configurationcache.serialization.codecs.BindingsBackedCodec.decode(BindingsBackedCodec.kt:59)
	at org.gradle.configurationcache.serialization.DefaultReadContext.read(Contexts.kt:267)
	at org.gradle.configurationcache.fingerprint.ConfigurationCacheFingerprintChecker.checkBuildScopedFingerprint(ConfigurationCacheFingerprintChecker.kt:58)
	at org.gradle.configurationcache.fingerprint.ConfigurationCacheFingerprintController.checkBuildScopedFingerprint(ConfigurationCacheFingerprintController.kt:246)
	at org.gradle.configurationcache.DefaultConfigurationCache$checkBuildScopedFingerprint$1.invokeSuspend(DefaultConfigurationCache.kt:463)
	at org.gradle.configurationcache.DefaultConfigurationCache$checkBuildScopedFingerprint$1.invoke(DefaultConfigurationCache.kt)
	at org.gradle.configurationcache.DefaultConfigurationCache$checkBuildScopedFingerprint$1.invoke(DefaultConfigurationCache.kt)
	at org.gradle.configurationcache.DefaultConfigurationCache$readFingerprintFile$1$1.invokeSuspend(DefaultConfigurationCache.kt:482)
	at org.gradle.configurationcache.DefaultConfigurationCache$readFingerprintFile$1$1.invoke(DefaultConfigurationCache.kt)
	at org.gradle.configurationcache.DefaultConfigurationCache$readFingerprintFile$1$1.invoke(DefaultConfigurationCache.kt)
	at org.gradle.configurationcache.ConfigurationCacheIO$withReadContextFor$1$1$1$1.invokeSuspend(ConfigurationCacheIO.kt:250)
	at org.gradle.configurationcache.ConfigurationCacheIO$withReadContextFor$1$1$1$1.invoke(ConfigurationCacheIO.kt)
	at org.gradle.configurationcache.ConfigurationCacheIO$withReadContextFor$1$1$1$1.invoke(ConfigurationCacheIO.kt)
	at org.gradle.configurationcache.serialization.RunningKt$runReadOperation$2.invokeSuspend(Running.kt:34)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115)
	at org.gradle.configurationcache.serialization.RunningKt.runToCompletion(Running.kt:56)
	at org.gradle.configurationcache.serialization.RunningKt.runReadOperation(Running.kt:33)
	at org.gradle.configurationcache.ConfigurationCacheIO.withReadContextFor$configuration_cache(ConfigurationCacheIO.kt:249)
	at org.gradle.configurationcache.DefaultConfigurationCache.readFingerprintFile(DefaultConfigurationCache.kt:480)
	at org.gradle.configurationcache.DefaultConfigurationCache.checkBuildScopedFingerprint(DefaultConfigurationCache.kt:461)
	at org.gradle.configurationcache.DefaultConfigurationCache.checkFingerprintAgainstLoadedProperties(DefaultConfigurationCache.kt:443)
	at org.gradle.configurationcache.DefaultConfigurationCache.checkFingerprint(DefaultConfigurationCache.kt:431)
	at org.gradle.configurationcache.DefaultConfigurationCache.access$checkFingerprint(DefaultConfigurationCache.kt:53)
	at org.gradle.configurationcache.DefaultConfigurationCache$checkFingerprint$1.invoke(DefaultConfigurationCache.kt:280)
	at org.gradle.configurationcache.DefaultConfigurationCache$checkFingerprint$1.invoke(DefaultConfigurationCache.kt:273)
	at org.gradle.configurationcache.ConfigurationCacheRepository$StoreImpl$useForStateLoad$2.invoke(ConfigurationCacheRepository.kt:167)
	at org.gradle.configurationcache.ConfigurationCacheRepository$StoreImpl$useForStateLoad$2.invoke(ConfigurationCacheRepository.kt:166)
	at org.gradle.configurationcache.ConfigurationCacheRepository$withExclusiveAccessToCache$1.create(ConfigurationCacheRepository.kt:249)
	at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90)
	at org.gradle.cache.internal.DefaultCacheAccess.withFileLock(DefaultCacheAccess.java:218)
	at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:188)
	at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingCache.withFileLock(DefaultCacheFactory.java:214)
	at org.gradle.configurationcache.ConfigurationCacheRepository.withExclusiveAccessToCache(ConfigurationCacheRepository.kt:247)
	at org.gradle.configurationcache.ConfigurationCacheRepository.access$withExclusiveAccessToCache(ConfigurationCacheRepository.kt:49)
	at org.gradle.configurationcache.ConfigurationCacheRepository$StoreImpl.useForStateLoad(ConfigurationCacheRepository.kt:166)
	at org.gradle.configurationcache.DefaultConfigurationCache.checkFingerprint(DefaultConfigurationCache.kt:273)
	at org.gradle.configurationcache.DefaultConfigurationCache.determineCacheAction(DefaultConfigurationCache.kt:223)
	at org.gradle.configurationcache.DefaultConfigurationCache.initializeCacheEntry(DefaultConfigurationCache.kt:116)
	at org.gradle.configurationcache.ConfigurationCacheBuildTreeLifecycleControllerFactory.createRootBuildController(ConfigurationCacheBuildTreeLifecycleControllerFactory.kt:52)
	at org.gradle.composite.internal.DefaultRootBuildState.<init>(DefaultRootBuildState.java:73)
	at org.gradle.composite.internal.BuildStateFactory.createRootBuild(BuildStateFactory.java:66)
	at org.gradle.composite.internal.DefaultIncludedBuildRegistry.createRootBuild(DefaultIncludedBuildRegistry.java:83)
	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:39)
	at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:65)
	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53)
	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:65)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:249)
	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:109)
	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36)
	at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:110)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
	at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:100)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:88)
	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:62)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:41)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:63)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:50)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:38)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
	at org.gradle.util.internal.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:49)
Caused by: java.lang.IllegalArgumentException: Could not find build ':'
	at org.gradle.composite.internal.DefaultIncludedBuildRegistry.getBuild(DefaultIncludedBuildRegistry.java:139)
	at org.gradle.configurationcache.serialization.codecs.BuildServiceProviderCodec.buildServiceRegistryOf(ProviderCodecs.kt:183)
	at org.gradle.configurationcache.serialization.codecs.BuildServiceProviderCodec.decode(ProviderCodecs.kt:175)
	at org.gradle.configurationcache.serialization.codecs.BindingsBackedCodec.decode(BindingsBackedCodec.kt:59)
	at org.gradle.configurationcache.serialization.codecs.FixedValueReplacingProviderCodec.decodeValue(ProviderCodecs.kt:123)
	at org.gradle.configurationcache.serialization.codecs.FixedValueReplacingProviderCodec.decodeProvider(ProviderCodecs.kt:109)
	at org.gradle.configurationcache.serialization.codecs.PropertyCodec.decode(ProviderCodecs.kt:268)
	at org.gradle.configurationcache.serialization.codecs.BindingsBackedCodec.decode(BindingsBackedCodec.kt:59)
	at org.gradle.configurationcache.serialization.DefaultReadContext.read(Contexts.kt:267)
	at org.gradle.configurationcache.serialization.beans.BeanPropertyReaderKt.readPropertyValue(BeanPropertyReader.kt:102)
	... 111 more

I found my exact issue discussed here Add a test case for the BuildService as ValueSource input failure · gradle/gradle@e079f11 · GitHub

See my comments in this related Pull Request:

As an experiment, I tried making ghAPIProvider a val but then also made it a Property so that I can use the property’s set method:

Yes, that’s usually the way to go.

This did not work. I got the same error as in my original post:

Sad, but as I said, was just a wild guess :slight_smile:

I found my exact issue discussed here

Have a look at the issue that is referenced in that pull request: Disallow BuildServices to be used as inputs to ValueSources obtained at configuration time · Issue #22337 · gradle/gradle · GitHub
It is currently in status “in progress”, so either in 8.1 this will work or fail with a more meaningful error.

1 Like

Thank you @Vampire for your help!

I would vote to allow this feature but understand if it is not feasible.

As the author of that issue is also working on it (or at least he moved it to “in progress”) and has in the issue description “either make it work or fail” as options, I guess he tries to make it work and let it fail if not possible. But feel free to make your voice heard in that ticket. :slight_smile:

1 Like

Our current plan is to make it fail with a nicer diagnostic message. A ValueSource with a BuildService input can only be obtained at execution time (in other words, it can be used as a task input). If the ValueSource is obtained at configuration time - its value becomes an input to the build configuration. Gradle has to evaluate the ValueSource in isolation to check if the configuration cache is still valid, similar to UP-TO-DATE checks. The isolation aspect makes it hard to support the BuildService. Additionally, if a BuildService is used as an input, its lifecycle becomes very complicated. I wouldn’t say it is impossible to support, but it isn’t something we’re going to address in the nearest future.

2 Likes