Skip to content

contains field condition throws a TypeError when the field value is an object #15534

Closed

Description

@joshdaugherty

Bug description

A contains (or includes) field condition throws TypeError: condition.lhs.includes is not a function when the target field's value is a plain object, such as a date field in range mode ({ start, end }) or a group field. The condition doesn't just evaluate to false: the exception escapes the validator.

On 6.x (0a58bd5ff), resources/js/components/field-conditions/Validator.js, prepareLhs() only turns the value into a string when it is not an object, so that an array keeps its includes() method:

// When performing lhs.includes(), if lhs is not an object or array, cast to string.
if ((operator === 'includes' || operator === 'includes_any') && !isObject(lhs)) {
    return lhs ? lhs.toString() : '';
}

isObject is lodash's, which is true for plain objects as well as arrays, so a plain object is passed through unchanged. passesIncludesCondition() then calls includes() on it without checking:

passesIncludesCondition(condition) {
    return condition.lhs.includes(condition.rhs);
}

An array has includes(); a plain object does not.

Every other operator already declines an object rather than throwing. passesCondition() guards it explicitly before its comparison:

if (isObject(condition.lhs)) {
    return false;
}

So the intended behavior for an object operand looks like "the condition fails", and only contains/includes is missing the guard. (contains_any and includes_any don't throw here: they never call includes() on the field value.)

The same code is in the latest release, v6.34.1 (prepareLhs() line 167, the guard at line 255, passesIncludesCondition() lines 262-263).

How to reproduce

  1. Add two fields to a blueprint, a date range and a field conditioned on it with contains:

    -
      handle: stay_dates
      field:
        type: date
        mode: range
    -
      handle: notes
      field:
        type: textarea
        if:
          stay_dates: 'contains 2026'
  2. Give stay_dates a value, e.g. { start: '2026-01-01', end: '2026-01-05' }.

  3. Evaluating notes' condition throws TypeError: condition.lhs.includes is not a function instead of returning false.

As a test in resources/js/tests/FieldConditionsValidator.test.js:

setValues({ stay_dates: { start: '2026-01-01', end: '2026-01-05' } });

expect(showFieldIf({ stay_dates: 'contains 2026' })).toBe(false);

On unchanged 6.x this throws the TypeError above.

Environment

Environment
Laravel Version: 13.24.0
PHP Version: 8.4.23
Composer Version: 2.10.2
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Timezone: UTC
Locale: en

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: NOT CACHED

Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Storage
public/storage: NOT LINKED

Statamic
Addons: 9
License Key: Not set
Sites: 255 (names redacted)
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.26.0 PRO

Statamic Addons
el-schneider/statamic-admin-bar: 0.3.2
jacksleight/statamic-bard-mutator: 3.0.5
jacksleight/statamic-bard-texstyle: 4.1.1
mitydigital/sitemapamic: 3.5.1
statamic/eloquent-driver: 5.10.0
statamic/ssg: 4.1.0
stillat/relationships: 2.4.0
studio1902/statamic-peak-tools: 9.2.0
uams-web/wordpress-importer: 0.19.0

Statamic Eloquent Driver
Addon Settings: file
Asset Containers: file
Assets: eloquent
Blueprints: file
Collection Trees: file
Collections: file
Entries: file
Fieldsets: file
Form Submissions: file
Forms: file
Global Sets: file
Global Variables: file
Navigation Trees: file
Navigations: file
Revisions: file
Sites: file
Taxonomies: file
Terms: file
Tokens: file

Installation

Other (please explain)

Reproduced in the statamic/cms repository's own test suite rather than in a site.

Additional details

A fix that fails the condition the same way the other operators do:

passesIncludesCondition(condition) {
    if (typeof condition.lhs?.includes !== 'function') {
        return false;
    }

    return condition.lhs.includes(condition.rhs);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions