zio icon indicating copy to clipboard operation
zio copied to clipboard

[ZIO 2] Receiving "could not find implicit value for evidence parameter of type zio.Tag" when attempting to use new service pattern

Open Nickersoft opened this issue 3 years ago • 7 comments

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.

Nickersoft avatar Jul 23 '22 20:07 Nickersoft

Hi! Is your service parameterized on a type? If so you may need to require implicit evidence that a tag exists for that type.

adamgfraser avatar Jul 23 '22 20:07 adamgfraser

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.

Nickersoft avatar Jul 23 '22 20:07 Nickersoft

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?

adamgfraser avatar Jul 23 '22 20:07 adamgfraser

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.

Nickersoft avatar Jul 23 '22 20:07 Nickersoft

Yeah that shouldn't be necessary. Maybe it would be worth trying to reproduce a simple version with Scastie to verify?

adamgfraser avatar Jul 23 '22 20:07 adamgfraser

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.

Nickersoft avatar Jul 23 '22 20:07 Nickersoft

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.

adamgfraser avatar Jul 23 '22 21:07 adamgfraser

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.

LeonardMeyer avatar Aug 22 '22 12:08 LeonardMeyer

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 avatar Aug 23 '22 14:08 LeonardMeyer

@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))
}

adamgfraser avatar Aug 23 '22 15:08 adamgfraser

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.

adamgfraser avatar Aug 28 '22 00:08 adamgfraser