Overview
Users are unable to add a required property of type Date and time.
Steps to Reproduce
- Create a code component
- Add a prop of type : Date and time select Date and time
- Mark it Allow multiple value - Unlimited
- Mark it as required - Example value as - 25/01/2026, 17:30
- Add to component
- Error : Failed to add to components
An error (HTTP 422) occurred while adding to components. Please check the browser console for more details.
Console :
{status: '422', errors: {…}, message: 'Multiple-cardinality prop "multiRequired" is required, but does not specify `minItems: 1`.'}
errors:
errors: Array(1)
0:
detail: "Multiple-cardinality prop \"multiRequired\" is required, but does not specify `minItems: 1`."
source: {pointer: ''}
[[Prototype]]:Object
length: 1
[[Prototype]]: Array(0)
[[Prototype]]: Object
message: "Multiple-cardinality prop \"multiRequired\" is required, but does not specify `minItems: 1`."
status: "422"
Comments
Comment #2
vipin.mittal18Comment #5
tim.plunkettNot just about date and time
Comment #6
tedbowComment #8
tedbowThanks @neha_bawankar for finding this and @chandu7929 for creating the fix.
After investigating the root cause of this bug, I'm taking a different approach than fixing the client-side code.
New approach: enforce minItems on the server see new MR https://git.drupalcode.org/project/canvas/-/merge_requests/1011
Instead of relying on the client to send minItems: 1 for required array props, JavaScriptComponent::updateFromClientSide() now enforces this directly:
Why this is better than the original fix
I worked on #3516754: Finalize how we ascertain a `type: array` (aka multiple-cardinality) SDC/JS prop value is empty and in hindsight think the frontend changes we added there were a mistake. We added logic to auto-set minItems: 1 when toggling required ON for array props, and to serialize/deserialize minItems in the code editor. The bug we're fixing now is evidence that this approach is fragile — the client should not be responsible for knowing and
correctly applying a schema constraint that the server already validates anyway. This fragility is compounded by the lack of e2e test coverage for the code editor, which means regressions in the frontend logic can go undetected.
The server is the authoritative source for this rule. Encoding it there means the constraint is enforced regardless of how the component data arrives, and the client doesn't need to track schema semantics.
What changed from #3516754: Finalize how we ascertain a `type: array` (aka multiple-cardinality) SDC/JS prop value is empty
The frontend changes added in #3516754: Finalize how we ascertain a `type: array` (aka multiple-cardinality) SDC/JS prop value is empty have been reverted:
Validation is added in \Drupal\canvas\Entity\JavaScriptComponent::updateFromClientSide. The backend validation in ComponentMetadataRequirementsChecker from #3516754: Finalize how we ascertain a `type: array` (aka multiple-cardinality) SDC/JS prop value is empty is retained — it still validates the constraint and runs after updateFromClientSide() has already enforced it.
Test coverage
Added JavascriptComponentTest::testUpdateFromClientSideMinItemsEnforcement()
Comment #9
tedbowHopefully tests will pass
Comment #11
tedbowComment #13
wim leers+1 for this shift. It's fine for the client-side representation to be simpler than the server-side ("stored/at-rest") representation: it allows aligning it with the exact needs of the UI. IOW: it's the pragmatic solution, especially given the reality there's no E2E tests for the code component editor UI (which is a subject out of scope here, but it is the reality and a forcing function).
(Note that there definitely is precedent; several config entities have client-side representations that more prominently diverge from the config schema-enforced server-side representation. It's why
\Drupal\canvas\Entity\CanvasHttpApiEligibleConfigEntityInterfaceexists!)