Closed (fixed)
Project:
Experience Builder
Version:
1.x-dev
Component:
Component sources
Priority:
Critical
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
21 Jul 2025 at 13:50 UTC
Updated:
7 Aug 2025 at 16:49 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
bnjmnmComment #3
tedbowI did some debugging on this.
I think what is happening is that "Required" string property does not error if an empty string is sent back
Tracked this down to
\JsonSchema\Constraints\UndefinedConstraint::validateCommonPropertiesSo it just checks if the property exists.
I checked and added
minLength: 1toheading.component.ymlfor "text" then it does fail validation on publish with an empty string.Not sure if this is the expected for SDC validation
I tested
tests/modules/xb_test_sdc/components/containers/two_column/two_column.component.ymland got rid of the `$ref: json-schema-definitions://experience_builder.module/column-width` for "width" so that it would just be treated as regular integer which would allow not filling out this field. I did get a "The property width is required." error when trying to publish in this case.I am not sure what the correct solution is here. We could do some shenanigans on the server-side to unset string properties that are empty and required.
Or we could add
minLength: 1to all string properties we want to be non-emptyOr we could add a new json-schema-definitions://experience_builder.module/non-empty-string` schema
Or we could add some sort of higher level validator that would make sure all require strings are not empty
Comment #4
penyaskito> Or we could add minLength: 1 to all string properties we want to be non-empty
That's my fav of the proposals. We would need to verify that there is not a
minLengthalready set, and of course SDC authors shouldn't need to do this if they already specified 'required'Comment #5
penyaskito... but we are limited by
a) metadata is read-only in core, we cannot alter it.
b) Ted tried this, and of course previews will show as broken until the value is filled, which isn't acceptable. Which means even if we could do that, we would need a way to only do it on publishing.
So the less elegant options
are the only realistic options right now.
Comment #6
tedbowI am looking into solutions in #5
Comment #8
tedbowStarted a rough MR. Manually testing it also stops publishing an empty string prop. Added basic test coverage
Comment #9
larowlanComment #10
tedbowaddressing the feedback
Comment #11
effulgentsia commentedThis is one we'll want to cherry pick to 0.x after it lands in 1.x, so tagging for that.
Comment #12
larowlanI think the root cause of this was these two commits added late to #3534601: Add a Video prop type to the Code Component editor; requires adding `file` as default `StaticPropSource`, `FileWidget` support and various infrastructure improvements
StaticPropSourcehereI think we should consider reverting these two commits (the first one only for changes to StaticPropSource).
Additionally, I think we should revisit the approach we took in #3529788: Required `type: string` (without other constraints, so "prose strings") props should fall back to empty string (even though invalid) while Content Author is typing, to allow matching live preview in most cases - I've reopened that and commented over there with my reasons - tl;dr I don't think we should allow the user to bypass clientside validation by editing any other field.
Comment #14
larowlanI added a different approach in https://git.drupalcode.org/project/experience_builder/-/merge_requests/1342 which is basically #12 and #3529788-21: Required `type: string` (without other constraints, so "prose strings") props should fall back to empty string (even though invalid) while Content Author is typing, to allow matching live preview in most cases
Comment #15
wim leersComment #16
wim leersResponded in-depth at #3529788-24: Required `type: string` (without other constraints, so "prose strings") props should fall back to empty string (even though invalid) while Content Author is typing, to allow matching live preview in most cases why I think the alternative MR is the wrong direction — tl;dr: this is a usability regression for the reasons @lauriii cited at #3529788-23: Required `type: string` (without other constraints, so "prose strings") props should fall back to empty string (even though invalid) while Content Author is typing, to allow matching live preview in most cases.
Comment #17
wim leersComment #19
wim leersThe mistake I made in #3529788: Required `type: string` (without other constraints, so "prose strings") props should fall back to empty string (even though invalid) while Content Author is typing, to allow matching live preview in most cases (besides it not being sufficiently narrow in special-casing allowing the empty string — follow-up MR on that issue to fix that) is that while
StaticPropSource::withValue()would complain hard and loud upon trying to load/edit a component tree with a requiredtype: string, minLength: 0SDC prop, it SHOULD have prevented it from being saved in the first place.@tedbow's test coverage nicely reproduces that, and it's the test coverage I should've added in #3529788. My bad. 🙈
The IMHO correct solution was actually pretty simple, and what I suggested ~24 hours ago (aka 2 MRs ago — MAN, this issue is moving fast 🙃 🤯) worked fine:
::isMinimalRepresentation(), similar to what #3529788 did for::withValue(), which SHOULD work because::buildPreviewRenderable()already is ignoring any validation errors precisely because it's for previewing — reduces the massive fail to a narrow one: a message mismatchStaticPropSource::isMinimalRepresentation()throw a different exception that::validateComponentInput()can catch, to allow this in turn to trigger the exceptions from SDCs themselves — thus replacing the hideous/confusing validation error linked above with the one we've been seeing all this time: the one from\Drupal\Core\Theme\Component\ComponentValidator::validateProps()— should be greenThoughts? :)
Comment #20
larowlanAdded a fourth (!) approach in MR
3537154-how-about-non-blankI think that if invalid data is not flagged by calling
validatethen we have reduced trust in our systems.The first approach I took was to add the
NonBlankconstraint toStringItemOverrideon thevalueproperty. But then I realised we never callvalidateon the field item list we have insideStaticPropSourceso that didn't do anything.So then I added a
validatemethod toPropSourceBaseand had\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInputcall that. But this blew up spectacularly because the field item list we have there has no entity parent and\Drupal\options\Plugin\Field\FieldType\ListItemBase::getSettableOptionsassumes we do.So then I backed all that out and instead injected the basic validator into
GeneratedFieldExplicitInputUxComponentSourceBaseand validated against aNonBlankconstraint for our required props in::validateComponentInput- which gets to the root of the issue - that json schema doesn't consider '' as invalid for a required items - whilst we do.That got the test from @tedbow to pass.
Sorry for adding another approach, I'm just concerned about the number of workarounds we are doing here.
Comment #23
tedbowI closed my MR. I think @larowlan's or @wimleers is probably the way to go. I think I understand how @wimleers' https://git.drupalcode.org/project/experience_builder/-/merge_requests/1346 works and it does solve the current problem
@larowlan's https://git.drupalcode.org/project/experience_builder/-/merge_requests/1352 seems promising because it gets to root of the problem, we consider required to mean not blank. but right now there are test failing around validation so assume it makes a bunch of other validation fail.
Comment #24
larowlanAh in #20 I had looked at the wrong MR and missed @wim leers's
That approach is fine with me, it is leaning on existing definitions of `isEmpty` in the field items inside the prop source, which is kind of what I was trying to achieve with the initial approaches of calling
validateon that field item list in #20I'll close my MR, sorry for the crossed wires.
Comment #26
wim leersThanks, @larowlan! 😊
I'm very relieved that this simple follow-up MR addresses the data integrity pieces — whew! 😇
I do very much agree we should do what you proposed at #3529788-29: Required `type: string` (without other constraints, so "prose strings") props should fall back to empty string (even though invalid) while Content Author is typing, to allow matching live preview in most cases! 👍
Comment #29
wim leersComment #30
wim leers@balintbrews is doing the cherry-picking to
0.x. This should pick cleanly.Comment #31
mayur-sose commentedI have tested the changes and confirmed that props text validation is working as expected. Users are now prevented from publishing when required text fields are left blank.
However, I observed the following issue: if a required text field is left blank and a publish attempt is made, the system correctly throws an error. But after entering a value into the text field and trying to publish again, the user is prompted to refresh the page with the message:
“Your latest change was not saved because the content was modified elsewhere since you loaded the page. Please refresh your browser to receive the latest changes and continue.”
Additionally, the publish tool displays this error:
“An item in the publish request did not match the expected format or value. Please refresh your page and try again.”
Refreshing the page resolves the issue, but this workflow could be improved so that the refresh message does not appear every time.
Comment #32
wim leersThanks!
Reproduced:

Investigated that and:
ui/src/features/editor/ConflictWarning.tsx, introduced in #3526907: For content entities add client support conflict detection via the `autoSaves' key\Drupal\experience_builder\Controller\UnmatchedItemInPublishRequest, introduced in #3520067: [Needs design] Confusing messages when publishing immediately after making changes: auto-save race conditionDigging deeper now.
Comment #33
wim leersComment #34
wim leersI couldn't reproduce #31 + #32 every time, but almost every time.
It's just a race condition in the auto-save system. It's literally what both of the referenced issues were about. We'll just need to harden against that. Created a follow-up: #3537866: Auto-save conflict if an item is already selected for publishing and another change is made.
This is still ready for backporting. The data integrity issue that this fixed is still real.
Comment #36
balintbrews