fast-json-stringify icon indicating copy to clipboard operation
fast-json-stringify copied to clipboard

Coercion rules are not working with anyOf

Open daniele-sarnari-blinkoo opened this issue 1 month ago • 2 comments

Prerequisites

  • [x] I have written a descriptive issue title
  • [x] I have searched existing issues to ensure the bug has not already been reported

Fastify version

5.6.2

Plugin version

6.1.1

Node.js version

v24.10.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

26.0.1

Description

When using AJV with Fastify, type coercion does not seem to work properly when the schema uses an anyOf definition that references another schema.

For example, in the following setup:

const schema = {
  $id: 'LogDetails',
  type: 'object',
  properties: {
    statePrevious: {
      anyOf: [
        // other possible schemas...
        { $ref: 'EntityStateUser#' },
      ],
    },
    stateNext: {
      anyOf: [
        // other possible schemas...
        { $ref: 'EntityStateUser#' },
      ],
    },
  },
  required: ['statePrevious', 'stateNext'],
};

const schemaEntityStateUser = {
  $id: 'EntityStateUser',
  type: 'object',
  properties: {
    id: { type: 'string', format: 'uuid' },
    email: { type: 'string' },
    name: { type: 'string' },
    surname: { type: 'string' },
    enabled: { type: 'boolean' },
    createdAt: { type: 'string' },
    roles: {
      type: 'array',
      items: { $ref: 'Role#' },
    },
  },
  required: [
    'entityType',
    'id',
    'email',
    'name',
    'surname',
    'enabled',
    'createdAt',
    'roles',
  ],
};

fastify.addSchema(schemaEntityStateUser);
fastify.addSchema(schema);

const input = {
  statePrevious: {
    id: 'abc',
    email: 'super secret email',
    name: 'Daniele',
    surname: 'Sarnari',
    enabled: 1, // should be coerced to boolean
    createdAt: '26/09/2022 15:49:02',
    roles: []
  },
  stateNext: {
    id: 'abc',
    email: 'super secret email',
    name: 'Daniele',
    surname: 'Sarnari',
    enabled: 1, // should be coerced to boolean
    createdAt: '26/09/2022 15:49:02',
    roles: []
  },
};

According to the AJV documentation on [type coercion](https://ajv.js.org/coercion.html), the enabled field (a boolean in the schema) should be coerced from 1 to true.

However, when the schema is wrapped inside an anyOf, coercion does not occur, and Fastify returns the following validation error:

The value of 'LogDetails#/properties/statePrevious' does not match schema definition.

(because ajv is not actively coercing the fields in the nested schemas) If the same setup is changed to use allOf instead of anyOf, coercion works as expected - the numeric value 1 is correctly converted to a boolean true.

Link to code that reproduces the bug

the description should be enough, if not just tell me and i will create a repository

Expected Behavior

No response

daniele-sarnari-blinkoo avatar Nov 12 '25 12:11 daniele-sarnari-blinkoo

May be related to https://github.com/fastify/fast-json-stringify/issues/290, but i am not 100% sure of that

daniele-sarnari-blinkoo avatar Nov 12 '25 12:11 daniele-sarnari-blinkoo

May be related to #290, but i am not 100% sure of that

No, that one is not involved in the input validation.

I think you are hitting this case: https://stackoverflow.com/a/34038277/3309466 The enabled prop is coerced to true ONLY IF the EntityStateUser schema validate it, but if a schema without the coercion matches the input object before, it is being skipped.

Anyway, I think it is not a Fastify issue unless you may provide a runnable issue to replicate that works with pure AJV and does not work with Fastify

Eomm avatar Nov 12 '25 17:11 Eomm