I figured out what's going on. JSONEncoder and JSONDecoder now support top-level "primitive" types (strings, numbers, booleans) by default. It's not implemented in JSONDecoder but apparently in JSONSerialization on iOS (13.1) and macOS (10.15.1). See the comments on bugs.swift.org/browse/SR-6163.