Problem/Motivation

Steps to reproduce

On Drupal 10.3+/11, \Drupal\datetime_range\DateTimeRangeTrait::renderStartEndWithIsoAttribute() declares a native string type on its $separator parameter. OptionalEndDateDateTimeRangeTrait::viewElements() passes $this->getSetting('separator') straight into it (line 29). PluginSettingsBase::getSetting() only merges defaultSettings() when the key is absent from the stored settings, so a stored explicit separator: null is returned as NULL and rendering fatals whenever an item has an end date different from the start date:

TypeError: Drupal\datetime_range\Plugin\Field\FieldFormatter\DateRangeDefaultFormatter::renderStartEndWithIsoAttribute():
Argument #2 ($separator) must be of type string, null given, called in
modules/contrib/optional_end_date/src/OptionalEndDateDateTimeRangeTrait.php on line 29

How a NULL ends up stored in real life: the separator is type: label in config schema, i.e. translatable. If a site translates an entity view display through the configuration translation UI (or a TMGMT job) and leaves the "Separator" field empty, the language collection stores content.FIELD.settings.separator: null. The base configuration still holds '-', so every config inspection looks healthy and the fatal only occurs when rendering in the translated language. Migrated or hand-written display YAML with an explicit null triggers the same crash.

The failure mode is particularly confusing when the field is rendered inside a BigPipe placeholder (e.g. a Views block): for users with a session, BigPipe catches the exception during streaming, logs it and silently drops the placeholder, while anonymous requests (no session, synchronous placeholder rendering) get a hard WSOD/500. The site therefore looks fine to logged-in administrators while anonymous visitors on one language get a 500.

Steps to reproduce

  1. Drupal 10.3+ or 11 with optional_end_date 2.0.0-beta1 or 2.0.0-beta2, a daterange field displayed with the default formatter, and a node whose end date differs from its start date.
  2. Enable configuration translation, translate the entity view display and leave "Separator" empty — or store separator: null in the display component settings by any other means.
  3. View the node in that language as an anonymous user: the TypeError above is thrown.

8.x-1.x is not affected: it used the separator in plain string concatenation (' ' . $separator . ' '), so a NULL silently degraded to an empty string. The regression appeared when 2.0.x started delegating to core's natively typed helper.

Proposed resolution

Cast the setting to string, restoring the 1.x tolerance:

$separator = (string) $this->getSetting('separator');

Patch attached; applies to both 2.0.x-dev and the 2.0.0-beta2 release.

Note: core's own DateTimeRangeTrait::viewElements() passes the same untyped setting into the same typed helper, so core is exposed to the identical crash — this module simply reaches it first because it swaps the class of the core daterange formatters. A core follow-up may be warranted.

Remaining tasks

Review / commit. Optionally a kernel test asserting that a formatter with 'separator' => NULL in its settings renders without error.

Comments

jrochate created an issue. See original summary.

jrochate’s picture

Status: Active » Needs review

  • birk committed e2c29b04 on 2.0.x
    fix: #3619717 TypeError: renderStartEndWithIsoAttribute(): Argument #2...
birk’s picture

Status: Needs review » Fixed

Thank you for the issue and patch.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.