- Shipped
- September 2, 2026 at 5:54 AM UTC
- Author
- Kamo
- Commit
- f7b5c7c
The clause tested si.label_ids, an array column on the search index. Nothing has ever written it — labelling a message inserts into email_metadata.message_labels, and neither the full indexer nor the folder-listing path sets the column. In production it is populated on zero of 547 rows, so the condition was an empty array containment test: false for every message, for every member. It was wrong a second time, and that one threw. The operand is whatever follows label: in the search box, which is a label's NAME — the backend's own suggestion says "Filter by label name", and the advanced panel builds label:<free text>. The clause cast that to UUID, so any real label name failed with invalid input syntax for type uuid: "work" verified against the live database. SearchService catches an index-search failure and falls back to IMAP, so a member searching label:work got no error and no labelled mail — just whatever IMAP made of the word, marked "(via IMAP)". So it now asks message_labels, resolving the name against the searching member's own labels. Case-insensitively: the name is typed by hand into a free-text box, and "Work" and "work" are one label to everyone except SQL. Scoping matters on both sides — the message must be the member's and so must the label, because label names are per-member and two members may each have a "Work". The replacement was run against the live database and returns rows rather than erroring. It matches nothing yet for a plainer reason than the bug: no member has created a label at all, so labels and message_labels are both empty.