Rules

R1001

Value mismatch

Suppose the spec says this:

paths:
  /approvals/{id}:
    get:
      responses:
        '200':
          description: Approval status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalStatus'
components:
  schemas:
    ApprovalStatus:
      type: object
      properties:
        status:
          type: string
          const: APPROVED
      required:
        - status

Expected response payload:

{
  "status": "APPROVED"
}

Note: The same expectation applies to requests reaching a Specmatic mock, or when validating examples as per the spec.

If the actual response contains:

{
  "status": "PENDING"
}

Specmatic raises R1001 because the response breaks the const rule declared in the schema.

Why this is a problem

Downstream systems depend on the enumerated value to drive business flows. Returning an unexpected value confuses consumers and causes conditional logic to fail.

How it can be fixed

Return the exact value mandated by the contract.

Corrected response:

{
  "status": "APPROVED"
}

R1002

Type mismatch

Suppose the spec says this:

paths:
  /customers:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerReference'
      responses:
        '201':
          description: Customer created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerReference'
components:
  schemas:
    CustomerReference:
      type: object
      properties:
        customerId:
          type: integer
      required:
        - customerId

Expected request payload:

{
  "customerId": 12345
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "customerId": "12345"
}

Specmatic raises R1002 because the field is a string instead of the integer type that the contract specifies.

Why this is a problem

Type mismatches break deserialization and validation logic, often causing requests to be rejected or data to be stored incorrectly.

How it can be fixed

Send the value using the data type defined in the specification.

Corrected request:

{
  "customerId": 12345
}

R1003

Constraint violation

Suppose the spec says this:

paths:
  /orders:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderIdentifier'
      responses:
        '201':
          description: Order created
components:
  schemas:
    OrderIdentifier:
      type: object
      properties:
        orderId:
          type: string
          pattern: ^INV-[0-9]{6}$
      required:
        - orderId

Expected request payload:

{
  "orderId": "INV-000001"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "orderId": "INV-1"
}

Specmatic raises R1003 because the value fails the regular-expression constraint declared for orderId.

Why this is a problem

Constraint violations lead to inconsistent identifiers and cause downstream services to reject the payload or misroute it.

How it can be fixed

Emit values that meet every constraint defined in the schema.

Corrected request:

{
  "orderId": "INV-000001"
}

R2001

Missing required property

Suppose the spec says this:

paths:
  /contacts:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Contact'
      responses:
        '201':
          description: Contact created
components:
  schemas:
    Contact:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string
          format: email

Expected request payload:

{
  "name": "Leela Fry",
  "email": "leela@example.com"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "name": "Leela Fry"
}

Specmatic raises R2001 because the required email property is missing.

Why this is a problem

Consumers expect required fields to be present so that essential processing (like sending notifications) can proceed without guessing or defaulting.

How it can be fixed

Always include every property listed in the required array.

Corrected request:

{
  "name": "Leela Fry",
  "email": "leela@example.com"
}

R2002

Missing optional property

Suppose the spec says this:

paths:
  /users:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserProfile'
      responses:
        '201':
          description: User created
components:
  schemas:
    UserProfile:
      type: object
      required:
        - username
      properties:
        username:
          type: string
        nickname:
          type: string
          description: Required when SSO integration is enabled.
      example:
        username: bender
        nickname: "Bender Bending Rodríguez"

Expected request payload (when SSO is enabled):

{
  "username": "bender",
  "nickname": "Bender Bending Rodríguez"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "username": "bender"
}

Specmatic raises R2002 because the interaction scenario (SSO enabled) describes nickname, yet the request omits it.

Why this is a problem

Scenario-specific optional fields still carry essential context. Omitting them when required by the example or description leads to incomplete user profiles.

How it can be fixed

Include optional properties whenever the documented scenario dictates their presence.

Corrected request:

{
  "username": "bender",
  "nickname": "Bender Bending Rodríguez"
}

R2003

Unknown property

Suppose the spec says this:

paths:
  /entities/{id}:
    get:
      responses:
        '200':
          description: Entity details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/KnownFieldsOnly'
components:
  schemas:
    KnownFieldsOnly:
      type: object
      additionalProperties: false
      properties:
        id:
          type: integer

Expected response payload:

{
  "id": 42
}

Note: The same expectation applies to requests reaching a Specmatic mock, or when validating examples as per the spec.

If the actual response contains:

{
  "id": 42,
  "unexpected": true
}

Specmatic raises R2003 because the payload introduces unexpected, which the contract forbids via additionalProperties: false.

Why this is a problem

Undocumented fields create ambiguity—clients might ignore them or throw errors, leading to unpredictable integrations.

How it can be fixed

Send only the properties defined in the contract, or extend the specification before emitting extra fields.

Corrected response:

{
  "id": 42
}

R3000

Discriminator mismatch

Suppose the spec says this:

paths:
  /payments:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Payment'
      responses:
        '202':
          description: Payment accepted
components:
  schemas:
    Payment:
      type: object
      oneOf:
        - $ref: '#/components/schemas/CardPayment'
        - $ref: '#/components/schemas/BankTransferPayment'
      discriminator:
        propertyName: type
        mapping:
          card: '#/components/schemas/CardPayment'
          bank-transfer: '#/components/schemas/BankTransferPayment'
    CardPayment:
      type: object
      required:
        - type
        - cardNumber
      properties:
        type:
          type: string
          const: card
        cardNumber:
          type: string
    BankTransferPayment:
      type: object
      required:
        - type
        - accountNumber
      properties:
        type:
          type: string
          const: bank-transfer
        accountNumber:
          type: string

Expected request payload:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "type": "bank-transfer",
  "cardNumber": "4111111111111111"
}

Specmatic raises R3000 because the discriminator points to the BankTransferPayment schema while the payload fields belong to the card branch.

Why this is a problem

Polymorphic contracts rely on discriminators to choose the correct schema. A mismatch means the payload cannot be validated or processed correctly.

How it can be fixed

Set the discriminator to the branch that matches the payload structure.

Corrected request:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

R3001

Missing discriminator

Suppose the spec says this:

paths:
  /payments:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Payment'
      responses:
        '202':
          description: Payment accepted
components:
  schemas:
    Payment:
      type: object
      required:
        - type
      oneOf:
        - $ref: '#/components/schemas/CardPayment'
        - $ref: '#/components/schemas/BankTransferPayment'
      discriminator:
        propertyName: type

Expected request payload:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "cardNumber": "4111111111111111"
}

Specmatic raises R3001 because the discriminator property type is absent, leaving the validator unable to pick a schema.

Why this is a problem

Without the discriminator, polymorphic payloads cannot be resolved to a concrete schema, so validation has no reference point.

How it can be fixed

Include the discriminator property specified by the contract alongside branch-specific fields.

Corrected request:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

R3002

Property not in any schema options

Suppose the spec says this:

paths:
  /payments:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/CardPayment'
                - $ref: '#/components/schemas/BankTransferPayment'
      responses:
        '202':
          description: Payment accepted
components:
  schemas:
    CardPayment:
      type: object
      required:
        - type
        - cardNumber
      properties:
        type:
          type: string
          const: card
        cardNumber:
          type: string
    BankTransferPayment:
      type: object
      required:
        - type
        - wireReference
      properties:
        type:
          type: string
          const: bank-transfer
        wireReference:
          type: string

Expected request payload (card branch):

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "type": "card",
  "wireReference": "ABC123"
}

Specmatic raises R3001 because wireReference belongs to the bank transfer schema, yet the discriminator selects the card branch.

Why this is a problem

Mixing properties from different schema options means no branch can validate the payload, leaving the consumer unsure how to interpret it.

How it can be fixed

Send only the properties defined for the selected schema option.

Corrected request:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

R3003

Property matches no schema option

Suppose the spec says this:

paths:
  /payments:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CardPayment'
      responses:
        '202':
          description: Payment accepted
components:
  schemas:
    CardPayment:
      type: object
      required:
        - type
        - cardNumber
      properties:
        type:
          type: string
          const: card
        cardNumber:
          type: string
          pattern: ^\d{16}$

Expected request payload:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

Note: The same validation applies when a contract test matches the response coming from the application to the spec, or when validating examples as per the spec.

If the actual request contains:

{
  "type": "card",
  "cardNumber": "123"
}

Specmatic raises R3002 because the provided values fail to satisfy the constraints of any schema option; the card branch rejects the short number, while other branches expect different discriminators.

Why this is a problem

When no schema option matches, the consumer cannot map the payload to a valid business object, so processing stops.

How it can be fixed

Adjust the values so they comply with at least one schema option’s requirements.

Corrected request:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

R3004

No matching schema option

Suppose the spec says this:

paths:
  /payments/{paymentId}:
    get:
      responses:
        '200':
          description: Payment details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payment'
components:
  schemas:
    Payment:
      type: object
      oneOf:
        - $ref: '#/components/schemas/CardPayment'
        - $ref: '#/components/schemas/BankTransferPayment'
      discriminator:
        propertyName: type
        mapping:
          card: '#/components/schemas/CardPayment'
          bank-transfer: '#/components/schemas/BankTransferPayment'

Expected response payload (card option):

{
  "type": "card",
  "cardNumber": "4111111111111111"
}

Note: The same expectation applies to requests reaching a Specmatic mock, or when validating examples as per the spec.

If the actual response contains:

{
  "type": "crypto",
  "wallet": "xyz"
}

Specmatic raises R3003 because the discriminator references an option (crypto) that the specification does not define.

Why this is a problem

Unsupported discriminator values leave consumers without a schema to validate against, so the payload cannot be trusted or processed.

How it can be fixed

Return a payload that matches a documented option, or extend the specification with a new schema before using the new discriminator.

Corrected response:

{
  "type": "card",
  "cardNumber": "4111111111111111"
}