Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

8. Throw on a filter that matches no column

Status: accepted

Context

Customer::search($term)->where('statuss', 'active') names a column that does not exist. An engine can ignore the constraint, or refuse the query.

Ignoring is the friendlier-looking option and the more dangerous one. A filter is usually there to remove results — a tenant scope, an archived flag, a visibility check. Dropping it silently returns more than the caller asked for, which in the multi-tenant case means returning another tenant’s records.

Decision

Throw when a filter names a column that is neither an indexed filter nor a column on the model’s table. Name the available columns in the message.

Consequences

A typo breaks the request loudly, at the first search, instead of quietly widening the result set. The message lists what the field could have been, which turns most occurrences into a one-second fix.

This is deliberately asymmetric with the missing-index case, which returns no results rather than throwing. The reasoning is which way each failure is safe: a filter that vanishes shows too much, so it must fail; a missing index shows nothing, and breaking every page in the application on a dropped table is worse than an empty result.

Applications that pass user-supplied field names into where() must validate them first — though a search that filters on arbitrary user-named columns has a larger problem than this exception.