[ZIO 2] Receiving "could not find implicit value for evidence parameter of type zio.Tag" when attempting to use new service pattern
Hey folks, I've been attempting to port my ZIO 1 codebase to ZIO 2 and am trying to adopt the new [service pattern] as described in the docs. However, I'm receiving errors on my calls to ZIO.serviceWithZIO and my ZLayer initializations that state "could not find implicit value for evidence parameter of type zio.Tag".
Any idea what could cause this? I'm using Bazel instead of SBT, so I need to declare my dependencies manually. I was receiving a similar error regarding zio.Trace until I included the dev.zio.stacktracer dependency in my build. Could this be something similar?
I noticed the code for Console declares a Tag variable directly, but this isn't mentioned anywhere in the docs so I didn't think it would be necessary.
Hi! Is your service parameterized on a type? If so you may need to require implicit evidence that a tag exists for that type.
Hey @adamgfraser! Thanks for such a quick response. Unfortunately, I'm still getting the hang of ZIO, so I'm not sure exactly what you mean 😅
My service is currently defined like this:
trait DownloadService {
def downloadResource(remotePath: String, localPath: String = null): Task[File]
}
object DownloadService {
def downloadResource(remotePath: String, localPath: String = null): RIO[DownloadService, File] =
ZIO.serviceWithZIO(_.downloadResource(remotePath, localPath))
}
// DownloadServiceLive case class omitted
object DownloadServiceLive {
val layer: TaskLayer[DownloadService] = ZLayer {
for {
logger ← ZIO.succeed(new Logger[DownloadService])
s3 ← ZIO.succeed(AmazonS3ClientBuilder.defaultClient())
bucket ← System.envOrElse("AWS_BUCKET", "").option
_ ← ZIO.when(bucket.isEmpty)(ZIO.fail(new Error("AWS_BUCKET must be set in order to use AWS functionality.")))
} yield new DownloadServiceLive(bucket.get, logger, s3)
}
}
I'm also a bit curious as why Tags are required in ZIO. I did a bit of reading on what they are, but am unsure how ZIO utilizes them and when or why you would need to specify them.
Tags are used to look up a service in the ZIO environment, so when you do serviceWithZIO[DownloadService] a tag for DownloadService, basically a type tag that represents that type as a value, should be generated and then used to look up the appropriate service in the environment. A parameterized service would be like DownloadService[A] so it doesn't look like you have that here.
Your example looks fine so that makes me think it is a Bazel issue. Do you have a dependency on ZIO Izumi Reflect?
Yep! My BUILD file includes both @maven//:dev_zio_izumi_reflect_2_12 and @maven//:dev_zio_izumi_reflect_thirdparty_boopickle_shaded_2_12. Is there anything I should need to import?
I noticed that adding lines such as `
implicit val tag: Tag[DownloadService] = Tag[DownloadService]
make the errors go away, but like I said, I didn't think it would be necessary.
Yeah that shouldn't be necessary. Maybe it would be worth trying to reproduce a simple version with Scastie to verify?
Hmm, yeah I just tested on Scastie. Seems to work. None of the ZIO dependencies like Izumi generate Tags at compile-time, do they? Maybe the Scala toolchain needs to be updated to include these dependencies.
Well the tags are like type tags or class tags so they are generated at compile time for whatever your types are but the fact that you could summon them seems to indicate that works okay.
For anyone having a similar issue following the migration to 2.0, check your imports. Apparently in ZIO 2 the Tag type for Izumi is now proxied through a new ZIO type with the same name. The ZIO methods' implicits require the ZIO type, hence the confusion.
@adamgfraser But that's only one case of error. When it just really can't summon a ZIO Tag I have the same failure as OP. I've managed to reproduce it though : https://scastie.scala-lang.org/vsuPBVBQRfu9TT54x3glsg
If you add implicit val tag = Tag[ZAkkaServer with Scope] it works though.
Nevermind, adding the Tag manually does not seem to be a great idea either. In my tests :
Exception in thread "zio-fiber-7,6,1,0" java.lang.Error: Defect in zio.ZEnvironment: Could not find {ZAkkaServer & Scope} inside ZEnvironment
I do have ZAkkaServer in my environment, the live implementation name is listed inside in the error. ZIO just seems confused because of the union type ?
@LeonardMeyer You just need to to add a type annotation:
import zio._
trait ZAkkaServer {
def start(routes: String): ZIO[Scope, Throwable, Unit]
}
object ZAkkaServer {
def start(routes: String): ZIO[ZAkkaServer with Scope, Throwable, Unit] =
ZIO.serviceWithZIO[ZAkkaServer](_.start(routes))
}
Going to close as there does not appear to be an issue here other than needing to specify the right type parameter but feel free to open again with a small reproducer if you are still having issues.