react-jsonschema-form
react-jsonschema-form copied to clipboard
Application freeze
Prerequisites
- [X] I have searched the existing issues
- [X] I understand that providing a SSCCE example is tremendously useful to the maintainers.
- [X] I have read the documentation
- [X] Ideally, I'm providing a sample JSFiddle, Codesandbox.io or preferably a shared playground link demonstrating the issue.
What theme are you using?
core
Version
5.x
Current Behavior
Using json schema generated from Prisma database causing application to freeze. (It has many nested references).
Expected Behavior
It should render form.
Steps To Reproduce
- Generate schema via prisma-json-schema-generator
- Copy paste schema into playground
Environment
Playground
Anything else?
Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"GeneralSection": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"title": {
"type": "string"
},
"description": {
"type": ["string", "null"]
},
"published": {
"type": "boolean",
"default": false
},
"slug": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/Tag"
}
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": ["string", "null"],
"format": "date-time"
},
"Project": {
"type": "array",
"items": {
"$ref": "#/definitions/Project"
}
},
"Work": {
"type": "array",
"items": {
"$ref": "#/definitions/Work"
}
},
"Post": {
"type": "array",
"items": {
"$ref": "#/definitions/Post"
}
}
}
},
"ImageRef": {
"type": "object",
"properties": {
"etag": {
"type": "string"
},
"public_id": {
"type": "string"
},
"type": {
"type": "string",
"default": "IMAGE",
"enum": ["IMAGE", "VIDEO", "THREE_D"]
},
"cld_url": {
"type": "string"
},
"path": {
"type": "string"
},
"filename": {
"type": "string"
},
"format": {
"type": "string"
},
"bytes": {
"type": "integer"
},
"description": {
"type": "string",
"default": ""
},
"width": {
"type": "integer"
},
"height": {
"type": "integer"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/Tag"
}
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": ["string", "null"],
"format": "date-time"
},
"Preferences": {
"anyOf": [
{
"$ref": "#/definitions/Preferences"
},
{
"type": "null"
}
]
},
"preferencesId": {
"type": ["integer", "null"]
},
"Work": {
"type": "array",
"items": {
"$ref": "#/definitions/Work"
}
},
"Project": {
"type": "array",
"items": {
"$ref": "#/definitions/Project"
}
}
}
},
"VideoRef": {
"type": "object",
"properties": {
"etag": {
"type": "string"
},
"type": {
"type": "string",
"default": "VIDEO",
"enum": ["IMAGE", "VIDEO", "THREE_D"]
},
"id": {
"type": ["string", "null"]
},
"vimeo_url": {
"type": ["string", "null"]
},
"sc_url": {
"type": ["string", "null"]
},
"yt_url": {
"type": ["string", "null"]
},
"title": {
"type": "string",
"default": "Untitled"
},
"duration": {
"type": ["string", "null"]
},
"definition": {
"type": ["string", "null"]
},
"description": {
"type": ["string", "null"]
},
"thumbnail": {
"type": ["string", "null"]
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/Tag"
}
},
"player_loop": {
"type": "boolean",
"default": true
},
"player_muted": {
"type": "boolean",
"default": false
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": ["string", "null"],
"format": "date-time"
},
"Preferences": {
"anyOf": [
{
"$ref": "#/definitions/Preferences"
},
{
"type": "null"
}
]
},
"preferencesId": {
"type": ["integer", "null"]
},
"Work": {
"type": "array",
"items": {
"$ref": "#/definitions/Work"
}
},
"Project": {
"type": "array",
"items": {
"$ref": "#/definitions/Project"
}
}
}
},
"Post": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"html": {
"type": ["string", "null"]
},
"general": {
"$ref": "#/definitions/GeneralSection"
},
"generalId": {
"type": "integer"
},
"author": {
"$ref": "#/definitions/User"
},
"authorId": {
"type": "integer"
}
}
},
"Preferences": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"creator_name": {
"type": "string",
"default": "Creator Name"
},
"homepage_heading": {
"type": "string",
"default": "Homepage"
},
"homepage_subheading": {
"type": "string",
"default": "Sub-Heading"
},
"homepage_background_image": {
"anyOf": [
{
"$ref": "#/definitions/ImageRef"
},
{
"type": "null"
}
]
},
"homepage_background_video": {
"anyOf": [
{
"$ref": "#/definitions/VideoRef"
},
{
"type": "null"
}
]
},
"enable_dashboard_darkmode": {
"type": "boolean",
"default": false
},
"enable_portfolio_pdf": {
"type": "boolean",
"default": false
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": ["string", "null"],
"format": "date-time"
},
"imageRefEtag": {
"type": ["string", "null"]
},
"videoRefEtag": {
"type": ["string", "null"]
}
}
},
"Project": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"subtitle": {
"type": ["string", "null"]
},
"start_date": {
"type": ["string", "null"],
"format": "date-time"
},
"end_date": {
"type": ["string", "null"],
"format": "date-time"
},
"venue": {
"type": ["string", "null"]
},
"images": {
"type": "array",
"items": {
"$ref": "#/definitions/ImageRef"
}
},
"videos": {
"type": "array",
"items": {
"$ref": "#/definitions/VideoRef"
}
},
"works": {
"type": "array",
"items": {
"$ref": "#/definitions/Work"
}
},
"general": {
"$ref": "#/definitions/GeneralSection"
},
"generalId": {
"type": "integer"
}
}
},
"Tag": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"images": {
"type": "array",
"items": {
"$ref": "#/definitions/ImageRef"
}
},
"videos": {
"type": "array",
"items": {
"$ref": "#/definitions/VideoRef"
}
},
"general": {
"type": "array",
"items": {
"$ref": "#/definitions/GeneralSection"
}
}
}
},
"SocialMedia": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"platform": {
"type": ["string", "null"]
},
"profileUrl": {
"type": ["string", "null"]
},
"username": {
"type": ["string", "null"]
},
"contactId": {
"type": "integer"
},
"Contact": {
"anyOf": [
{
"$ref": "#/definitions/Contact"
},
{
"type": "null"
}
]
}
}
},
"Contact": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"email": {
"type": ["string", "null"]
},
"socialmedia": {
"type": "array",
"items": {
"$ref": "#/definitions/SocialMedia"
}
},
"userId": {
"type": "integer"
},
"Profile": {
"anyOf": [
{
"$ref": "#/definitions/Profile"
},
{
"type": "null"
}
]
}
}
},
"Profile": {
"type": "object",
"properties": {
"userId": {
"type": "integer"
},
"html_statement": {
"type": ["string", "null"]
},
"html_additional": {
"type": ["string", "null"]
},
"portfolio_pdf_url": {
"type": ["string", "null"],
"default": "https://archive.org/download/jakubkanna_PORTFOLIO_2024/jakubkanna_PORTFOLIO_2024.pdf"
},
"contact": {
"type": "array",
"items": {
"$ref": "#/definitions/Contact"
}
},
"User": {
"$ref": "#/definitions/User"
}
}
},
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"email": {
"type": "string"
},
"hash": {
"type": "string"
},
"salt": {
"type": "string"
},
"posts": {
"type": "array",
"items": {
"$ref": "#/definitions/Post"
}
},
"Profile": {
"type": "array",
"items": {
"$ref": "#/definitions/Profile"
}
}
}
},
"Work": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"dimensions": {
"type": ["string", "null"]
},
"year": {
"type": ["integer", "null"]
},
"images": {
"type": "array",
"items": {
"$ref": "#/definitions/ImageRef"
}
},
"videos": {
"type": "array",
"items": {
"$ref": "#/definitions/VideoRef"
}
},
"projects": {
"type": "array",
"items": {
"$ref": "#/definitions/Project"
}
},
"general": {
"$ref": "#/definitions/GeneralSection"
},
"generalId": {
"type": "integer"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": ["string", "null"],
"format": "date-time"
}
}
}
},
"type": "object",
"properties": {
"generalSection": {
"$ref": "#/definitions/GeneralSection"
},
"imageRef": {
"$ref": "#/definitions/ImageRef"
},
"videoRef": {
"$ref": "#/definitions/VideoRef"
},
"post": {
"$ref": "#/definitions/Post"
},
"preferences": {
"$ref": "#/definitions/Preferences"
},
"project": {
"$ref": "#/definitions/Project"
},
"tag": {
"$ref": "#/definitions/Tag"
},
"socialMedia": {
"$ref": "#/definitions/SocialMedia"
},
"contact": {
"$ref": "#/definitions/Contact"
},
"profile": {
"$ref": "#/definitions/Profile"
},
"user": {
"$ref": "#/definitions/User"
},
"work": {
"$ref": "#/definitions/Work"
}
}
}
There is a lot going on in this schema! I think it is going to take someone a while to figure out all of the things going on here.
I discovered one issue when I removed all properties in the schema other than the recursive anyOf arrays with refs:
Simplified / Broken schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ImageRef": {
"type": "object",
"properties": {
"Preferences": {
"anyOf": [
{
"$ref": "#/definitions/Preferences"
},
{
"type": "null"
}
]
}
}
},
"VideoRef": {
"type": "object",
"properties": {
"Preferences": {
"anyOf": [
{
"$ref": "#/definitions/Preferences"
},
{
"type": "null"
}
]
}
}
},
"Preferences": {
"type": "object",
"properties": {
"homepage_background_image": {
"default": null,
"anyOf": [
{
"$ref": "#/definitions/ImageRef"
},
{
"type": "null"
}
]
},
"homepage_background_video": {
"default": null,
"anyOf": [
{
"$ref": "#/definitions/VideoRef"
},
{
"type": "null"
}
]
}
}
}
},
"type": "object",
"properties": {
"imageRef": {
"$ref": "#/definitions/ImageRef"
},
"videoRef": {
"$ref": "#/definitions/VideoRef"
},
"preferences": {
"$ref": "#/definitions/Preferences"
}
}
}
The issue here is that RJSF is defaulting to the first anyOf option, which causes infinite recursion (either when it tries to generate the default form state, or when it builds the form).
You can break that cycle by settings the default value to null in the properties of preferences:
Simplified / fixed schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ImageRef": {
"type": "object",
"properties": {
"Preferences": {
"anyOf": [
{
"$ref": "#/definitions/Preferences"
},
{
"type": "null"
}
]
}
}
},
"VideoRef": {
"type": "object",
"properties": {
"Preferences": {
"anyOf": [
{
"$ref": "#/definitions/Preferences"
},
{
"type": "null"
}
]
}
}
},
"Preferences": {
"type": "object",
"properties": {
"homepage_background_image": {
"default": null,
"anyOf": [
{
"$ref": "#/definitions/ImageRef"
},
{
"type": "null"
}
]
},
"homepage_background_video": {
"default": null,
"anyOf": [
{
"$ref": "#/definitions/VideoRef"
},
{
"type": "null"
}
]
}
}
}
},
"type": "object",
"properties": {
"imageRef": {
"$ref": "#/definitions/ImageRef"
},
"videoRef": {
"$ref": "#/definitions/VideoRef"
},
"preferences": {
"$ref": "#/definitions/Preferences"
}
}
}
However, fixing this issue in the base schema doesn't seem to totally fix the problem, so there is more to investigate.
There is a lot going on in this schema! I think it is going to take someone a while to figure out all of the things going on here.
I discovered one issue when I removed all properties in the schema other than the recursive
anyOfarrays with refs:Simplified / Broken schema The issue here is that RJSF is defaulting to the first
anyOfoption, which causes infinite recursion (either when it tries to generate the default form state, or when it builds the form).You can break that cycle by settings the default value to null in the properties of preferences:
Simplified / fixed schema However, fixing this issue in the base schema doesn't seem to totally fix the problem, so there is more to investigate.
Thanks for you reply, for now I will change my approach, it's hard to find out what's going on.
I suspect it might work if you replaced all of your recursive schemas with anyOf defaulting to null. RJSF currently doesn't detect recursion when it builds the component tree, so it never terminates when it encounters a case that defaults to infinite recursion.
To fix this in RJSF, we would probably need to add recursion detection to the React component tree, and then bail when we encounter infinite recursion when we have no form data to show. In those cases, we could render a button to allow the user to render another level of the tree.
A similar issue exists in the toIdSchema util where it doesn't handle the same types of recursive schemas that recurse infinitely 'by default'. This would also need to be fixed to properly support these schemas.