softwaremill / softwaremill/tapir

[BUG] Ambigous implicit values with multi-level enumeratum's enums

Open
#1,333 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Scala
Stars
1.5k
Forks
468
Avg merge
5h 37m
Merged PRs (30d)
34

Description

Tapir version: 0.18.0-M17

Scala version: 2.13.6

Describe the bug

When you have inner enum inside other enum and both of them extends TapirCodecEnumeratum trait - compile will fail with error:

  • ambiguous implicit values:
    both method schemaForEnumEntry in trait TapirCodecEnumeratum of type [E <: enumeratum.EnumEntry](implicit enum: enumeratum.Enum[E]): sttp.tapir.Schema[E]
    and method schemaForEnumEntry in trait TapirCodecEnumeratum of type [E <: enumeratum.EnumEntry](implicit enum: enumeratum.Enum[E]): sttp.tapir.Schema[E]
    match expected type sttp.tapir.Schema.Typeclass[Outer.Inner]
    implicit val schema: Schema[ClassWithInner] = Schema.derived[ClassWithInner]

  • magnolia: could not find Schema.Typeclass for type Outer.Inner
    in parameter 'i' of product type ClassWithInner
    implicit val schema: Schema[ClassWithInner] = Schema.derived[ClassWithInner]

How to reproduce?

Example of code:


import enumeratum._
import io.circe.Codec
import io.circe.generic.semiauto.deriveCodec
import sttp.tapir.Schema
import sttp.tapir.codec.enumeratum.TapirCodecEnumeratum

case class ClassWithOuter(i: Outer)       // compiles fine
case class ClassWithInner(i: Outer.Inner) // won't compile

object ClassWithInner {
  implicit val codec: Codec[ClassWithInner]   = deriveCodec[ClassWithInner]
  implicit val schema: Schema[ClassWithInner] = Schema.derived[ClassWithInner]
}

sealed trait Outer extends EnumEntry

object Outer extends Enum[Outer] with CirceEnum[Outer] with TapirCodecEnumeratum {

  case object TestOnj extends Outer
  sealed trait Inner  extends Outer

  object Inner extends Enum[Inner] with CirceEnum[Inner] with TapirCodecEnumeratum {
    case object TestInner extends Inner
    override def values: IndexedSeq[Inner] = findValues
  }

  // uncomment this to fix compile
  //implicit val innerSchema: Schema[Inner] = Inner.schemaForEnumEntry[Inner]

  override def values: IndexedSeq[Outer] = findValues
}

By the way, circe does not have this issue. I guess, it is because CirceEnum have the type.

Additional information

Project code: https://github.com/DenisNovac/tapir-enumeratum

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with TapirCodecEnumeratum and the nested Outer.Inner reproducer in the issue, then inspect how Schema.derived resolves schemas for enum entries. Verify the fix by compiling ClassWithInner without the workaround innerSchema definition, while preserving the existing ClassWithOuter behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.