Ajv-errors custom error message

Hi,

I’m attempting to override the error messaging. Please see my schema and ui schema:

Schema:

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "type": "object",
  "properties": {
    "Cat": {
      "type": "string"
    },
    "Dog": {
      "type": "string"
    },
    "Fish": {
      "type": "string"
    }
  },
  "required": ["Cat", "Dog"],
  "errorMessage": {
    "required": {
      "Cat": "Cat is required"
    }
  }
}

UI Schema:

{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Group",
      "elements": [
        {
          "type": "Control",
          "scope": "#/properties/Cat",
          "label": "Cat"
        },
        {
          "type": "Control",
          "scope": "#/properties/Dog",
          "label": "Dog"
        },
        {
          "type": "Control",
          "scope": "#/properties/Fish",
          "label": "Fish"
        }
      ]
    }
  ]
}

and in the component I am using createAjv and then using ajvErrors:

  ajv = createAjv({
    allErrors: true,
    verbose: true,
  });

  constructor() {
    ajvErrors(this.ajv);
    // Also tried this:
    // this.ajv = ajvErrors(this.ajv);
  }

html:

<jsonforms
  [data]="data"
  [schema]="schema"
  [uischema]="uischema"
  [renderers]="renderers"
  [i18n]="i18n"
  [ajv]="ajv"
  (dataChange)="onDataChange($event)"
  validationMode="ValidateAndShow"
></jsonforms>

Notice, the override is kind of recognised (because the default error now doesn’t show) but the new message doesn’t show on that field.

Screenshot 2023-09-11 at 17.43.52

Any help appreciated.

I’d like to be able to override errors generically, in this case, replacing all “required” messages with something else with the option to tailor some and ideally, defining these somewhere outside of the schemas and perhaps in the json-forms props?

Hi @charlie ,
did you already have a look at the i18n documentation for errors on the website: i18n - JSON Forms ?

You should be able to translate errors via your translate function provided as part of the i18n object handed into the jsonforms component. Thereby, JsonForms derives an i18n key from the error.
This is a property specific key (e.g. Cat.error.required for your Cat property). To generally provide a translation for all errors of a type, i18n key error.<error> (e.g. error.required) is used.

Could this solve your problem?

Hi,
I have exactly the same issue. Is the internationalization the only way to solve this issue? Since I don’t really need the internationalization support it would be a bit overkill for me. Custom ajv-errors would be sufficient.
Could you resolve this issue?
If i18n is the way to solve this, where could I find a good example that integrates i18n into the json-forms component?

Integrating ajv-errors with JSON Forms should be straightforward.

Still the i18n support is probably even easier and gives you more control. There is nothing to “integrate” there, you just need to hand over a translation function. For every message you are not interested in, you simply hand back the default message. See here for the docs.

Hi Stefan,
Thank you for your quick reply!
Since I would like to adjust the error messages inside the JSON schema, it would be probably the easiest to just use the ajv-errors.
So my JSON looks like this:
{
“title”: “Assessment Type”,
“type”: “object”,
“required”: [
“basic_information”
],
“errorMessage”: “Please select an assessment type”,
“properties”: {
“basic_information”: {
“title”: “Add description of the purpose of assessment”,
“type”: “string”
}
}
}
And I created the Ajv object like this:
interface State {
ajv: Ajv;
}
data(): State {
return {
ajv: addErrors(createAjv()),
};
},
And I integrated the Ajv object into my json-forms component like this:
<json-forms
@change=“(event) => update(event, currentTab.namespace, currentTab.name)”
:data=“assessment.data[currentTab.namespace]”
:schema=“JSON.parse(currentTab.schema)”
:uischema=“JSON.parse(currentTab.uiSchema)”
:renderers=“renderers”
:ajv=“ajv”
>

Still I don’t see my custom error message but I see no error at all:


Is there anything I am missing? I just don’t know what could possibly lead to it that the custom error message just isn’t shown. Any help would be appreciated!

Hi @daywin,

Please first make sure whether you correctly integrated ajv-errors with ajv. You can do so by manually using your customized ajv instance to validate your schema/data inspecting the returned errors whether they look like you expect.

Hi Stefan,
I did print it out to the console and the console.log(validate.errors) Is telling me the correct value, which is this here:
0: Object { schemaPath: “#/errorMessage”, keyword: “errorMessage”, message: “Please select an assessment type”, … }
Still in my form there is no error message shown:


Is there anything else you could suggest?
Thank you very much for your help!

The error looks weird: Its schemaPath is #/errorMessage but this is not a property in your JSON Schema. What is the instance path of the error?

Okay that is right, here might be an error. The instance path is empty:
0: Object { schemaPath: “#/errorMessage”, keyword: “errorMessage”, message: “Please select an assessment type”, … }
data: Object { }
instancePath: “”
keyword: “errorMessage”
message: “Please select an assessment type”
params: Object { errors: (1) […] }
parentSchema: Object { title: Getter & Setter, type: Getter & Setter, required: Getter & Setter, … }
schema: “Please select an assessment type”
schemaPath: “#/errorMessage”
Is there something wrong with my json schema? From the examples from ajv-errors it seemed that my JSON schema would be written correctly.

So the problem as I see it is the following:
We have the following schema:

title: Basic Information
type: object
required: ['basic_information']
properties:
  basic_information:
    title: "Add some basic information"
    placeholder: "Please specify some basic information"
Now using json-forms with standard ajv, the ajv error will look like the following:
instancePath: ""
keyword: "required"
message: "must have required property 'basic_information'"
params: {
  missingProperty: "basic_information"
}

This is then mapped to the component in https://github.com/eclipsesource/jsonforms/blob/f905c828a5e2ab1f32f831b245d1d381895c6628/packages/core/src/reducers/core.ts#L367 and via the standard i18n translation displayed as “is a required property”.
There is more data in the error message, but the rest seems not relevant.
However, when we try to use custom error messages with ajv-errors, the schema will look like

title: Basic Information
type: object
required: ['basic_information']
properties:
  basic_information:
    title: "Add some basic information"
    placeholder: "Please specify some basic information"
errorMessage:
  required:
    basic_information: "The basic information property is required"
but the ajv error will now look like
instancePath: ""
keyword: "errorMessage"
message: "The basic information property is required"
params: {
  errors: [
    {
      instancePath: ""
      keyword: "required"
      message: "must have required property 'basic_information'"
      params: {
        missingProperty: "basic_information"
      }
    }
  ]
}

however, this does not get mapped to the correct property anymore (because the path has to be constructed from the nested errors), so it seems as if validation doesn’t occur.
Is there any workaround known for this?

Hi @daywin,

As you noticed ajv-errors is modifying the structure of the returned error object of AJV instead of just exchanging the message. Especially the returned keyword: 'errorMessage' is a custom keyword which JSON Forms does not know anything about. JSON Forms does not know to inspect and how to interpret the custom params then.

In general we also show custom keyword errors, however the issue here is that the instancePath is against the object itself, not the property. For keyword: 'required' we know that the error is actually referring to the instancePath + <missingProperty>, see here. For the custom keyword we can’t know that.

So that is the issue why the error does not show up for you: The error is not mapped against the property and the renderer for the object itself does not show errors.

To workaround the issue you can either:

  • check whether ajv-errors can be configured and/or modified to not modify the structure of the returned error
  • use custom renderers / bindings to iterate yourself over the errors of the form to find these custom errors and map them appropriately
  • use the JSON Forms i18n support which also allows you to modify the error messages. In your custom “translator” you can also walk through your schema and read the errorMessage from there if that is what you want to see as a pattern.

Hi Stefan,
Thank you for your reply!
One more question to the i18n support. Do I have to create a separate schema for that? Or is it somehow possible to integrate it into the current schema?
Because maintaining another schema just for custom error messages would be a no-go.
Kind regards,
Davin

Hi @daywin,

the i18n support is basically just a function which is called by JSON Forms with the current context, expecting a string in return. So no extra schema etc. is required. Please have a look at the documentation, copy the first translator example and you are good to go.

I don’t understand this question. Using a modified schema is exactly the approach you would take when using ajv-errors as it expects all the custom keywords with the modified messages to be contained in the schema. Using JSON Forms i18n instead you don’t even need to modify your original schema as long as you can somehow derive your custom messages.