vulcan icon indicating copy to clipboard operation
vulcan copied to clipboard

imapError message not returned when type decoded inside an Option

Open jensraaby opened this issue 4 years ago • 2 comments

We have some codecs which bootstrap the String codec and convert values to our own internal enumeratum values. The schema models the data as string or null, which we attempt to model as Option[OurEnumType].

The decoding works fine, except when an unexpected String comes through. The error message presented is Exhausted alternatives for type org.apache.avro.util.Utf8 - rather than the underlying failure with our custom message.

Broadly our codec looks a bit like the following:

case class MyThing(value: String)
object MyThing {
  def fromString(s: String): Option[MyThing] = if (s=="thing") Some(MyThing(s)) else None
  implicit val codec: Codec[MyThing] =
    Codec.string.imapError(str => fromString(str).toRight(AvroError(s"$str is not what we want")))(_.value)
}

Is there a way to make the underlying error message bubble up? This issue led to a bit of head scratching because the stack trace didn't identify where the problem was either.

jensraaby avatar Mar 17 '21 10:03 jensraaby

I managed to get something which emits the correct error message with the following, but it would be nice to have something in the API to support this, similar to how Circe works

implicit val myThingCodec: Codec[Option[MyThing]] =
Codec
  .option[String]
  .imapError[Option[MyThing]] ({
    case Some(str) => fromString(str).map(Some(_)).toRight(AvroError(s"$str not what we want"))
    case None => Right(None)
  })(maybeMyThing => maybeMyThing.map(myThing => myThing.value))

jensraaby avatar Mar 18 '21 14:03 jensraaby

This is really a special case of a more general issue, which is that union decoders don't propagate specific errors when all alternatives fail. It could be nice to expose the reason why each alternative failed.

That said, even if we don't do that it might also be worth special-casing the Option codec so that it reports the underlying error when failing to decode a non-null value.

bplommer avatar Mar 28 '21 19:03 bplommer