Daniel Phillips
08/14/2025, 10:27 AM"message": "discriminator: oneOf subschemas (or referenced schemas) must have \"properties/transactionType\""
What I cannot understand is why it's complaining about the transactionType not being declared within subschemas, when all of them explicityly define it alongside a fixed enum value.
Here is a sample of what my schema definitions look like:
Transaction:
required:
- transactionDetails
- transactionType
type: object
properties:
transactionType:
type: string
description: 'Type of transaction. Used as a discriminator for polymorphic deserialization.'
example: transaction_a
transactionDetails:
$ref: '#/components/schemas/TransactionDetails'
description: Transaction Details
discriminator:
propertyName: transactionType
oneOf:
- $ref: '#/components/schemas/TransactionA'
- $ref: '#/components/schemas/TransactionB'
TransactionA:
required:
- transactionDetails
- transactionType
type: object
description: Transaction A Details
allOf:
- $ref: '#/components/schemas/Transaction'
- type: object
properties:
transactionDetails:
$ref: '#/components/schemas/TransactionADetails'
transactionType:
type: string
description: Constant discriminator identifying this transaction subtype
readOnly: true
example: transaction_a
enum:
- transaction_a
TransactionB:
required:
- transactionDetails
- transactionType
type: object
description: Transaction B Details
allOf:
- $ref: '#/components/schemas/Transaction'
- type: object
properties:
transactionDetails:
$ref: '#/components/schemas/TransactionBDetails'
transactionType:
type: string
description: Constant discriminator identifying this transaction subtype
readOnly: true
example: transaction_b
enum:
- transaction_bMatt (pactflow.io / pact-js / pact-go)
Matt (pactflow.io / pact-js / pact-go)
Transaction is oneOf TransactionA or TransactionB, which is a Transaction (which is one of TransactionA, TransactionB …)Matt (pactflow.io / pact-js / pact-go)
openapi: 3.1.0
info:
title: Pet Polymorphism Example
version: '1.0'
components:
schemas:
Animal:
type: object
required:
- pet_type
discriminator:
propertyName: pet_type
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
Dog:
type: object
required:
- pet_type
properties:
pet_type:
type: string
const: dog
barkVolume:
type: integer
Cat:
type: object
required:
- pet_type
properties:
pet_type:
type: string
const: cat
whiskerLength:
type: numberDaniel Phillips
08/14/2025, 12:54 PMTransaction is an abstract parent class and `TransactionA`/`TransactionB` inherit from it. allOf within the subschemas is be being used to inherit all properties from Transaction closer to the allOf example here.Matt (pactflow.io / pact-js / pact-go)
Daniel Phillips
08/14/2025, 1:09 PMDaniel Phillips
08/14/2025, 2:37 PMtail property which we want to be inherited by all subschemas. In order to do so we have to utilise allOf within each subschema to reflect the polymorphic nature of the code structure.
With using a discriminator on Animal, we then have to use a oneOf property too. This results in the recursive nature and is how our OpenAPI specification are being generated by spingdoc .
What are your recommendations for getting around this?
openapi: 3.1.0
info:
title: Pet Polymorphism Example
version: 1.0.0-oas3.1
components:
schemas:
Animal:
type: object
properties:
tail:
type: string
examples:
- huge
required:
- pet_type
discriminator:
propertyName: pet_type
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
Dog:
type: object
required:
- pet_type
properties:
pet_type:
type: string
const: dog
barkVolume:
type: integer
Cat:
type: object
required:
- pet_type
allOf:
- $ref: '#/components/schemas/Animal'
- type: object
properties:
pet_type:
type: string
const: cat
whiskerLength:
type: numberDaniel Phillips
08/14/2025, 7:52 PMTransactionA using springdoc-openapi-ui, which extends from the main Transaction object, we get the following YAML schema.
Transaction
Transaction:
required:
- transactionDetails
- transactionType
type: object
properties:
transactionType:
type: string
description: 'Type of transaction. Used as a discriminator for polymorphic deserialization. Valid exam
example: loan_renewal
transactionDetails:
$ref: '#/components/schemas/TransactionDetails'
description: Base Transaction type. The actual type is determined by the 'transactionType' property.
discriminator:
propertyName: transactionType
mapping:
loan: '#/components/schemas/TransactionA'
oneOf:
- $ref: '#/components/schemas/TransactionA'
TransactionA
TransactionA:
required:
- transactionDetails
- transactionType
type: object
description: Loan Transaction Details
allOf:
#With or without the $ref property we get the error.
- $ref: '#/components/schemas/Transaction'
- type: object
properties:
transactionDetails:
$ref: '#/components/schemas/TransactionADetails'
transactionType:
type: string
description: Constant discriminator identifying this transaction subtype
readOnly: true
example: loan
enum:
- loan
This causes discriminator mapping issues within Pactflow schema validation due to the allOf which gets generated for inheritance.
To get this to be valid I can manually edit the schema to be like so:
TransactionA:
required:
- transactionDetails
- transactionType
type: object
description: Loan Transaction Details
properties:
transactionDetails:
$ref: '#/components/schemas/TransactionADetails'
transactionType:
type: string
description: Constant discriminator identifying this transaction subtype
readOnly: true
example: loan
enum:
- loan
So is this expected behaviour of Pactflow? Even without the #ref back up to the parent to inherit properties, having properties inside of an allOf seems to break the discriminator mapping?Matt (pactflow.io / pact-js / pact-go)
ajv directly.
If ajv doesn’t support it, we’d need to do something additional in PactFlow’s tooling to support it (e.g. a workaround, effectively)Matt (pactflow.io / pact-js / pact-go)