Skip to content

Search palette lists identically-named tags with no way to tell them apart; picking the wrong one returns no results #915

Description

@Deeds67

Split out of #894 for follow-up. The navigation half of #894 is fixed in #895 and the filename half in #896this is the remaining, still-open part, and it is the likely cause of the original "tapping the suggested Strand tag returns Keine Ergebnisse" report.

Problem

The search palette can list two entries with the same visible name and no way to distinguish them. Picking the wrong one returns "No results".

The reporter of #894 saw exactly this: their third screenshot shows "Strand" listed twice under Tags. I originally dismissed that as cosmetic. It isn't — it's the defect.

Why duplicates appear

Tags in Immich are per-user (tag.userId; uniqueness is enforced per user via TagRepository.getByValue(userId, value)). Two users can each own a tag named Strand with different ids.

TagRepository.getAll(userId) deliberately returns own tags plus tags reachable through a shared space:

getAll(userId: string) {
  return this.db
    .selectFrom('tag')
    .select(columns.tag)
    .where((eb) => this.ownedOrSpaceAccessible(eb, userId))
    .orderBy('value')
    .execute();
}

That scoping is correct and intentional for the tag explorer. The problem is what the palette does with the result.

Failure shape — common in setups where one admin account owns all externally-mounted libraries and everyone else is a Space member:

  • the member owns a tag Strand with zero assets
  • the admin owns a tag Strand carrying all the photos
  • both appear in the palette, rendered identically
  • picking the member's own one → "No results"

A second, independent source of visual duplicates: tag-row.svelte renders only item.name, not item.value. A nested tag travel/japan and a top-level japan therefore both render as "japan".

Contributing factors

  1. No owner/space disambiguation in the rowtag-row.svelte renders {item.name} and nothing else.
  2. No nesting contextvalue (the full path) is available but unused, so tags at different paths collide visually.
  3. No emptiness signal — a tag with no assets the viewer can access is suggested identically to one with thousands.
  4. The provider matches on name and slices to 5 (global-search-manager.svelte.ts, tags provider), so two same-named tags can consume two of the five slots without either being useful.

Related observation (may be the same root cause)

Reported separately during #896 validation: tapping the "Tags" section header (not an individual entry) produced a filter chip literally labelled Tags and "No results". Unconfirmed which element was actually hit — every palette section heading is a non-interactive Command.GroupHeading, so this needs the post-tap URL to diagnose:

  • /photos?tags=<uuid> → a real tag named "Tags" with no accessible assets — same class of bug as above
  • /photos?tags=Tags → a non-uuid is being passed as a tag id — a distinct bug

active-filters-bar renders tagNames.get(tagId) ?? tagId, so a chip showing a category-like word is consistent with either.

Possible approaches (not yet decided)

  • Disambiguate in the row — show the full value path and/or an owner/space badge when two visible entries share a name
  • De-duplicate by name in the provider, preferring the tag that actually has accessible assets
  • Suppress empty tags — filter out tags with no viewer-accessible assets (needs a count the palette doesn't currently fetch; cost to be assessed against the existing 20k tag-cache ceiling)
  • Merge semantics — treat same-named tags as one filter and pass all matching ids

Worth deciding deliberately: options 2 and 3 change what the palette shows, and hiding a user's own tag entirely could be surprising in the other direction.

Repro

Requires two accounts (invisible to a library owner testing alone):

  1. Admin owns the assets and a tag Strand applied to them; shares them into a Space.
  2. Second user is a member of that Space and has their own tag named Strand with no assets.
  3. As the member, open the search palette and type Strand.
  4. Two identical "Strand" rows appear. Picking the member's own one returns "No results".

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions