Conditional required not showing errors

Hello everyone.
I need some help to undestand what is happening or what I am doing wrong.
I am currently using

"@jsonforms/core": "^3.4.0",
    "@jsonforms/material-renderers": "^3.4.0",
    "@jsonforms/react": "^3.4.0",
    "ajv": "^8.6.1",
    "ajv-errors": "^3.0.0",
    "ajv-formats": "^2.1.0"

In a react proyect.
This is my json-schema

{
    type: 'object',
    properties: {
      Cipher: {
        type: 'string',
        oneOf: [
          { const: 'rc4_hmac', title: 'rc4_hmac' },
          { const: 'aes128_cts_hmac_sha1_96', title: 'aes128_cts_hmac_sha1_96' },
          { const: 'aes256_cts_hmac_sha1_96', title: 'aes256_cts_hmac_sha1_96' },
        ]
      },
    },
    anyOf: [
      {
        properties: {
          CCACHE: {
            type: 'string',
            isNotEmpty: true,
            errorMessage: {
              isNotEmpty: 'is a required property',
            },
          },
        },
        required: ['CCACHE'],
      },
      {
        allOf: [
          {
            properties: {
              Username: { type: 'string', minLength: 1 }
            },
            required: ['Username'],
          },
          {
            properties: {
              Domain: { type: 'string', minLength: 1 }
            },
            required: ['Domain'],
          },
          {
            properties: {
              Key: { type: 'string', minLength: 1 }
            },
            required: ['Key'],
          },
        ],
      },
    ],
    required: [
      'Cipher',
    ],
  }

And this is how I am dealing with the state change

// validator
const ajv = new Ajv({
  allErrors: true,
});
ajvErrors(ajv);
registerValidatorIsNotEmpty(ajv);
registerValidatorAtLeastOneTrue(ajv);
addFormats(ajv);
ajv.addFormat('target_selection', true);
ajv.addFormat('file_selection', true);
ajv.addFormat('add_delete', true);
const handleFormChange = useCallback((data: FormData) => {
    console.log(data);
    setFormData(data);
    const isValid = ajv.validate(schema, data);
    console.log(isValid);
    setSubmitDisabled(!isValid);
  }, [schema]);
<JsonForms
          ajv={ajv}
          schema={schema}
          uischema={schemaUi}
          data={formData}
          cells={materialCells}
          renderers={[
            ...materialRenderers,
            { tester: passwordTester, renderer: PasswordFieldRenderer },
            { tester: targetSelectionTester, renderer: TargetSelectionRenderer },
            { tester: fileSelectionTester, renderer: FileSelectionRenderer },
            { tester: addDeleteTester, renderer: AddDeleteRenderer },
            { tester: textTester , renderer: TextRenderer}
          ]}
          onChange={({ data, errors }) => {
            console.log(errors)
            handleFormChange(data);
          }}
        />

My expected behaviour is that Cipher must always be requiered, cant be empty.
Second for setting the submit enable CCache must not be empty OR Username, Domain and Key the three of them should have any value.
If they are all empty Cipher and CCache must show error.
With the current code, when all the fields are empty, no errors are displayed on the ui.
If Cipher has any value, nothing else shows error.
If either I fill out CCACHE or the other 3, the error displays correctly on the UI for Cipher
Checking the log, when theres no values set, this is the errors from the onChange

0
: 
{instancePath: '', schemaPath: '#/anyOf/0/required', keyword: 'required', params: {…}, message: "must have required property 'CCACHE'"}
1
: 
{instancePath: '', schemaPath: '#/anyOf/1/allOf/0/required', keyword: 'required', params: {…}, message: "must have required property 'Username'"}
2
: 
{instancePath: '', schemaPath: '#/anyOf/1/allOf/1/required', keyword: 'required', params: {…}, message: "must have required property 'Domain'"}
3
: 
{instancePath: '', schemaPath: '#/anyOf/1/allOf/2/required', keyword: 'required', params: {…}, message: "must have required property 'Key'"}
4
: 
{instancePath: '', schemaPath: '#/anyOf', keyword: 'anyOf', params: {…}, message: 'must match a schema in anyOf'}
5
: 
{instancePath: '', schemaPath: '#/required', keyword: 'required', params: {…}, message: "must have required property 'Cipher'"}
length
: 
6

When CCache or 3 other fields are filled and Cipher is empty this is the errors list which is correct

0
: 
{instancePath: '', schemaPath: '#/required', keyword: 'required', params: {…}, message: "must have required property 'Cipher'"}
length
: 
1

And this one is if Cipher with value, but others are empty

0
: 
{instancePath: '', schemaPath: '#/anyOf/0/required', keyword: 'required', params: {…}, message: "must have required property 'CCACHE'"}
1
: 
{instancePath: '', schemaPath: '#/anyOf/1/allOf/0/required', keyword: 'required', params: {…}, message: "must have required property 'Username'"}
2
: 
{instancePath: '', schemaPath: '#/anyOf/1/allOf/1/required', keyword: 'required', params: {…}, message: "must have required property 'Domain'"}
3
: 
{instancePath: '', schemaPath: '#/anyOf/1/allOf/2/required', keyword: 'required', params: {…}, message: "must have required property 'Key'"}
4
: 
{instancePath: '', schemaPath: '#/anyOf', keyword: 'anyOf', params: {…}, message: 'must match a schema in anyOf'}
length
: 
5

Any ideas what is happening.

Hi!

The issue is that ajv-errors is modifying the required messages in a way so that JSON Forms no longer knows how to map them to the UI. You can compare the errors emitted by AJV with and without ajv-errors to see the difference.

Without ajv-errors the empty form looks like this:

To solve this you could either:

  • not use ajv-errors. Usually you can solve the same requirements with JSON Forms’ i18n support or ajv-i18n, OR
  • modify the errors from ajv before using them, either via an own AJV plugin or via a JSON Forms middleware, to correct the error.

See also this PR in which the topic was also discussed. A solution is also linked in there.


Unrelated to the issue, but you don’t need to validate yourself in handleFormChange. JSON Forms already validates for you, see the errors array in onChange. Now you are basically validating twice all the time.

If you prefer validating outside of JSON Forms, then you don’t need to hand over AJV to JSON Forms. Instead hand over validationMode="NoValidation" and hand over all calculated errors in additionalErrors.