Peculiar Swift JSON decoding bug

I'm decoding a semi-large JSON file using Codable and I'm running into to some very peculiar issues. The error I'm running into is about a missing key that I know is present in every entry. I have provided details about the setup below. If you want to try reproducing this, here's the full JSON file.

Details

I'm decoding the following JSON:

{
  "minecraft:zombified_piglin_spawn_egg": {
    "id": 821,
    "category": 6,
    "rarity": 0,
    "max_stack_size": 64,
    "max_damage": 0,
    "is_fire_resistant": false,
    "is_complex": false,
    "translation_key": "item.minecraft.zombified_piglin_spawn_egg",
    "spawn_egg_color_1": 15373203,
    "spawn_egg_color_2": 5009705,
    "spawn_egg_entity_type": 104,
    "class": "SpawnEggItem"
  },
  // ... 970 more entries similar to this
}

I'm using the following codable struct:

public struct PixlyzerItem: Decodable {
  public var id: Int
  public var category: Int?
  public var rarity: ItemRarity
  public var maximumStackSize: Int
  public var maximumDamage: Int
  public var isFireResistant: Bool
  public var isComplex: Bool
  public var translationKey: String
  public var block: Int?
  public var className: String

  private enum CodingKeys: String, CodingKey {
    case id
    case category
    case rarity
    case maximumStackSize = "max_stack_size"
    case maximumDamage = "max_damage"
    case isFireResistant = "is_fire_resistant"
    case isComplex = "is_complex"
    case translationKey = "translation_key"
    case block
    case className = "class"
  }
}

And decoding with JSONDecoder().decode([String: PixlyzerItem].self, from: data) throws the following error:

Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "translation_key", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "minecraft:dropper", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"translation_key\", intValue: nil) (\"translation_key\").", underlyingError: nil))

I have checked, and every single entry includes a value for translation_key. I have tried decoding with JSONSerialization.jsonObject(with: data) and it has a value for every key except for the translation_key of each item. I tried with a reduced test case (only a single entry, the one from the error) and the error didn't occur. This leads me to believe that this is a bug in Foundation's JSON implementation.

What platform?

Works for me on mac and returns expected result.
let json = """
{
  "minecraft:zombified_piglin_spawn_egg": {
    "id": 821,
    "category": 6,
    "rarity": 0,
    "max_stack_size": 64,
    "max_damage": 0,
    "is_fire_resistant": false,
    "is_complex": false,
    "translation_key": "item.minecraft.zombified_piglin_spawn_egg",
    "spawn_egg_color_1": 15373203,
    "spawn_egg_color_2": 5009705,
    "spawn_egg_entity_type": 104,
    "class": "SpawnEggItem"
  }
}
"""

public typealias ItemRarity = Int

public struct PixlyzerItem: Decodable {
  public var id: Int
  public var category: Int?
  public var rarity: ItemRarity
  public var maximumStackSize: Int
  public var maximumDamage: Int
  public var isFireResistant: Bool
  public var isComplex: Bool
  public var translationKey: String
  public var block: Int?
  public var className: String

  private enum CodingKeys: String, CodingKey {
    case id
    case category
    case rarity
    case maximumStackSize = "max_stack_size"
    case maximumDamage = "max_damage"
    case isFireResistant = "is_fire_resistant"
    case isComplex = "is_complex"
    case translationKey = "translation_key"
    case block
    case className = "class"
  }
}

func test() {
    let data = json.data(using: .utf8)!
    let v = try! JSONDecoder().decode([String: PixlyzerItem].self, from: data)
    print(v)
    print("done")
}

["minecraft:zombified_piglin_spawn_egg": JT.PixlyzerItem(id: 821, category: Optional(6), rarity: 0, maximumStackSize: 64, maximumDamage: 0, isFireResistant: false, isComplex: false, translationKey: "item.minecraft.zombified_piglin_spawn_egg", block: nil, className: "SpawnEggItem")]

The reduced case that you used does work, but the full json file doesn't (linked in original post)

Oh.. I figured out what's happening. I was looking at a different commit to the one I was using :| I'm tired.

1 Like