question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ConfiguredJsonEncoder broken on upgrade from 0.8.0 to 0.9.1.

See original GitHub issue

I’m attempting to upgrade a large enterprise Scala project from Circe 0.8.0 to 0.9.1 and getting a compiler error on the following code:

object Parsing {
  // This is where the implicit `Configuration` comes from.
  import JsonWithTypeField.implicits._

  // Note: Circe needs empty companion objects after any extending case classes for all sealed traits below.
  // This is to work around SI-7046 issues in a stable and repeatable way.
  // See https://circe.github.io/circe/codec.html#warnings-and-known-issues, point 5, for more information.

  @ConfiguredJsonCodec
  sealed trait ValidationErrorHandling

  object AttributeValidation {
    @ConfiguredJsonCodec
    sealed trait AttributeValidationErrorHandling extends ValidationErrorHandling
    case object Strict extends AttributeValidationErrorHandling
    case object EmptyAsDelete extends AttributeValidationErrorHandling
    case object EmptyAndFailureAsDelete extends AttributeValidationErrorHandling
    object AttributeValidationErrorHandling
  }

  object ActionValidation {
    @ConfiguredJsonCodec
    sealed trait ActionValidationErrorHandling extends ValidationErrorHandling
    case object Strict extends ActionValidationErrorHandling
    case object AllowEmpty extends ActionValidationErrorHandling
    case object AllowEmptyAndFailure extends ActionValidationErrorHandling
    object ActionValidationErrorHandling
  }

  object ValidationErrorHandling

  // ...
}

This was compiling happily on circe 0.8.0 but fails to compile on circe 0.9.1:

[info] Compiling 29 Scala sources to [...]/target/scala-2.11/classes ...
[error] [...]/Parsing.scala:19:4: could not find Lazy implicit value of type io.circe.generic.extras.decoding.ConfiguredDecoder[com.foo.ValidationErrorHandling]
[error]   @ConfiguredJsonCodec
[error]    ^
[error] one error found
[error] (foo / Compile / compileIncremental) Compilation failed
[error] Total time: 18 s, completed 12-Mar-2018 16:12:12

After exhausting all the options of moving around wrapper object types and ensuring I wasn’t being hit by the ghosts of SI-7046, I managed to track down that I could still have this example compile on 0.9.0-M2 but not 0.9.0-M3 - a quick git bisect later revealed that the issue was introduced somewhere in the change at https://github.com/circe/circe/commit/5193b5b8bcc3910535d036f09adee259493c7cb8.

Unfortunately, I can’t seem to make a reproducible test case from just the above code. It’s worth noting that there are other decoders that reference these above too, I’m just posting the code snippet that actually fails compilation.

I’m not really able to say exactly what about this change causes the compilation in this project to fail, mainly because the commit in question is way over my head, but I’m happy to assist with reproducing the error in any way needed!

Issue Analytics

  • State:open
  • Created 6 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

9reactions
travisbrowncommented, Mar 13, 2018

This comment is a minimization for the sake of voting / discussion. The question is whether the following code should compile (I’m using @JsonCodec here, but you’d see the same thing with either auto or semiauto):

import io.circe.generic.JsonCodec

@JsonCodec sealed trait Base

object Foo { case object Qux extends Base }
object Bar { case object Qux extends Base }

It doesn’t compile on 0.9.x, but does on 0.8 and earlier, where it has the following goofy behavior:

scala> import io.circe.Decoder, io.circe.syntax._
import io.circe.Decoder
import io.circe.syntax._

scala> Decoder[Base].decodeJson((Foo.Qux: Base).asJson).map(_ == Bar.Qux)
res0: scala.util.Either[io.circe.DecodingFailure,Boolean] = Right(true)

Specifically, Shapeless’s “union” doesn’t have unique keys, so either case object will get encoded in such a way that it will be decoded as the one whose wrapper object name is lexicographically first.

I’m inclined to think not compiling is the right thing to do here, since there are no other (known) cases where a generically derived encoder-decoder pair won’t round-trip values (at least for circe-generic), but I’m open to counter-arguments, or you can just vote:

👍: it should compile (the pre-0.9 behavior); 👎: it should not compile (the current behavior).

1reaction
travisbrowncommented, Mar 12, 2018

Ugh, that sounds plausible but unfortunate. Luckily we could fix it in 0.9.2 (which I’ve been meaning to release for the validate fix for the past few days, anyway).

Read more comments on GitHub >

github_iconTop Results From Across the Web

ConfiguredJsonEncoder broken on upgrade from 0.8.0 to 0.9.1.
ConfiguredJsonEncoder broken on upgrade from 0.8.0 to 0.9.1.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found