Bases: multi-value properties can be returned as scalars at runtime, causing list comparison filters to fail

Description

In Obsidian Bases, properties that are configured as multi-value properties can still be returned as scalar values at runtime when the underlying YAML contains only one value.

This makes filters difficult to write reliably, because a property that conceptually represents a list may sometimes behave like a list and sometimes like a scalar/string/link.

This became visible when comparing Task Notes properties such as:

  • projects
  • assignees
  • contexts

against properties on the current embedded note, such as:

  • this.projects
  • this.attendees
  • this.meeting

Observed behavior

Some properties are configured as multi-value fields in Obsidian. For example:

  • projects: multi-value property
  • assignees: multi-value property

However, at runtime in Bases, the returned type depends on how the value is represented in the note.

For example, a frontmatter value with a single item may be returned as a scalar/link/string rather than a list.

This means that a filter may behave differently depending on whether the note currently has one value or multiple values.

Example

A task note may have:

assignees: "[[Jane Doe]]"

Another task note may have:

assignees:
  - "[[Jane Doe]]"
  - "[[John Smith]]"

Both represent the same conceptual property: a multi-value assignees field.

But in Bases filters, the first can behave like a scalar value, while the second behaves like a list.

Why this is a problem

It makes otherwise simple filters unreliable.

For example, in an embedded Base inside a meeting note, I want to show tasks where at least one task assignee is also one of the meeting attendees.

The intuitive filter would be something like:

assignees.containsAny(this.attendees)

But this can fail with a type error such as:

Failed to evaluate a filter: Type error in "containsAny", parameter "values": Expected String, given List.

The robust workaround is:

list(assignees).filter(list(this.attendees).contains(value)).length > 0

This works because both sides are explicitly normalized to lists first.

Expected behavior

For properties configured as multi-value fields, Bases should ideally return a consistent list type at runtime, even when there is only one value.

For example:

assignees: "[[Jane Doe]]"

and:

assignees:
  - "[[Jane Doe]]"

should both behave consistently as lists in Bases when assignees is configured as a multi-value property.

Alternative expected behavior

If Bases intentionally preserves the YAML scalar/list distinction, then this should be clearly documented, because the current behavior is surprising for properties configured as multi-value fields in Obsidian.

In that case, Bases should ideally provide a first-class list-overlap function, for example:

overlaps(assignees, this.attendees)

or:

assignees.overlaps(this.attendees)

so users do not need to write verbose defensive filters such as:

list(assignees).filter(list(this.attendees).contains(value)).length > 0

Impact

This affects embedded Bases that compare properties between the current note and the listed notes.

Common examples:

  • task assignees vs meeting attendees
  • task projects vs meeting projects
  • task contexts vs current meeting/person context

This makes filters hard to understand and maintain in the UI, especially for non-technical users.

Suggested improvements

Any of the following would help:

  1. Return consistent list values for properties configured as multi-value fields.
  2. Add a built-in list-overlap function.
  3. Make containsAny() accept a dynamic list argument.
  4. Improve documentation and error messages around scalar vs list runtime behavior.

I’m a bit perplexed by the example here:

… As from my quick tests, this seems to only be possible if the assignees key wasn’t initially set as a list before entering a first value in Properties but later on :thinking: (and the notes containing only one value written as a string weren’t updated after changing the key type)… or, potentially if the key type was left on Automatic (which let Obsidian infer the type of the key depending on the value it holds) instead of being manually set to List and the value was written from Source as a simple string instead of an item in a list …

In any cases and imho :smile:, you shouldn’t have notes with the same key where there’s some kind of “type mismatch” :woman_shrugging:
I mean, this feel a bit strange to me :innocent: