ITADN

`JsonCodec.jsonCodec` produces inconsistent schema when type hierarchy has nested `sealed trait`s

#3946Closeddontgitit 创建于 2026-02-04
bug
D
dontgititcommented
**Describe the bug** Consider the following type hierarchy: ```scala sealed trait Animal derives JsonCodec, Schema sealed trait Dog extends Animal sealed trait Fish extends Animal case class GoldenRetriever(name: String) extends Dog case class Bass(color: String) extends Fish ``` When using `zio-json`, instances are discriminated by their instance class name. When using `zio-http` with `zio-schema`, generating the json schema via `JsonCodec.jsonCodec[Schema[Animal]]` produces a json schema where `Animal` is first discriminated by `Dog` or `Fish`. **To Reproduce** Steps to reproduce the behaviour: [Scastie link ](https://scastie.scala-lang.org/UQliolhTSzWJdS6Dxsc9Ww) **Expected behaviour** The schema produced by `JsonCodec` should be the same one that's produced by `zio-json`; specifically, the intermediate `trait`s should not be visible in the schema. **Screenshots** <img width="867" height="787" alt="Image" src="https://github.com/user-attachments/assets/a82fb98b-6595-4ac1-931a-b0be53d38fe0" /> **Additional context** For context, I was trying to generate a spec (json/openapi) that I could feed to an LLM so it could understand/build values of type `Animal` for me. A workaround (though kind of ugly) is to NOT extend `Animal` in the intermediate traits: ```scala sealed trait Animal derives JsonCodec, Schema sealed trait Dog { self: Animal => } sealed trait Fish { self: Animal => } case class GoldenRetriever(name: String) extends Animal, Dog case class Bass(color: String) extends Animal, Fish ``` Then the generated schema is correct: ```json { "$schema" : "https://json-schema.org/draft/2020-12/schema", "oneOf" : [ { "type" : "object", "properties" : { "GoldenRetriever" : { "$ref" : "#/$defs/GoldenRetriever" } }, "additionalProperties" : false, "required" : [ "GoldenRetriever" ] }, { "type" : "object", "properties" : { "Bass" : { "$ref" : "#/$defs/Bass" } }, "additionalProperties" : false, "required" : [ "Bass" ] } ], "$defs" : { "GoldenRetriever" : { "type" : "object", "properties" : { "name" : { "type" : "string" } }, "required" : [ "name" ] }, "Bass" : { "type" : "object", "properties" : { "color" : { "type" : "string" } }, "required" : [ "color" ] } } } ``` I wonder if this issue has a similar underlying cause as [one I previously reported](https://github.com/zio/zio-http/issues/3801)? Full sample code: ```scala import zio.* import zio.json.* import zio.json.ast.* import zio.schema.* import zio.schema.codec.* import zio.schema.codec.json.* import zio.http.endpoint.openapi.* sealed trait Animal derives JsonCodec, Schema sealed trait Dog extends Animal sealed trait Fish extends Animal case class GoldenRetriever(name: String) extends Dog case class Bass(color: String) extends Fish val animal: Animal = Bass("brown") // produces: // {"Bass":{"color":"brown"}} println(animal.toJson) val jsonSchema = JsonSchema.jsonSchema(Schema[Animal]) // produces: //{ // "$schema" : "https://json-schema.org/draft/2020-12/schema", // "oneOf" : [ // { // "type" : "object", // "properties" : { // "Dog" : { // "$ref" : "#/$defs/Dog" // } // }, // "additionalProperties" : false, // "required" : [ // "Dog" // ] // }, // { // "type" : "object", // "properties" : { // "Fish" : { // "$ref" : "#/$defs/Fish" // } // }, // "additionalProperties" : false, // "required" : [ // "Fish" // ] // } // ], // "$defs" : { // "GoldenRetriever" : { // "type" : "object", // "properties" : { // "name" : { // "type" : "string" // } // }, // "required" : [ // "name" // ] // }, // "Dog" : { // "oneOf" : [ // { // "type" : "object", // "properties" : { // "GoldenRetriever" : { // "$ref" : "#/$defs/GoldenRetriever" // } // }, // "additionalProperties" : false, // "required" : [ // "GoldenRetriever" // ] // } // ] // }, // "Bass" : { // "type" : "object", // "properties" : { // "color" : { // "type" : "string" // } // }, // "required" : [ // "color" // ] // }, // "Fish" : { // "oneOf" : [ // { // "type" : "object", // "properties" : { // "Bass" : { // "$ref" : "#/$defs/Bass" // } // }, // "additionalProperties" : false, // "required" : [ // "Bass" // ] // } // ] // } // } //} println(jsonSchema.toJsonPretty) ``` with the following `build.sbt`: ```scala scalaVersion := "3.7.4" libraryDependencies ++= Seq( "org.scastie" %% "runtime-scala" % "1.0.0-SNAPSHOT", "dev.zio" %% "zio-json" % "0.8.0", "dev.zio" %% "zio" % "2.1.24", "dev.zio" %% "zio-schema-json" % "1.7.6", "dev.zio" %% "zio-http" % "3.8.1", "dev.zio" %% "zio-schema" % "1.7.6" ) scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", "-feature", "-unchecked" ) ```
关闭于 2026-03-03 0 条评论