The two boring causes worth ruling out before anything clever, because they are quick and they are common on tables that have grown fast.
Statistics are out of date. The planner decides using a sample of the table's contents, gathered periodically. On a table that has recently grown or changed shape a lot, those numbers can describe a table that no longer exists. Run an analyse on the table and re-check the plan. This takes seconds and it fixes a surprising share of these.
The index was never actually built, or was built on something slightly different from what you think. Check what exists on the table rather than what is in your migration file, particularly if you have been running migrations against a database that has diverged.
And one thing specific to using an ORM, since that is this room: look at the SQL that was actually sent. Log it. The query you wrote in the ORM and the query the database received are not always the same shape, and an ORM that wraps a column, adds a cast, or reorders conditions will produce exactly your symptom while your ORM code looks correct.
That is also the general lesson here: this is a database question wearing an ORM costume, and the fastest route to the answer is always to get the real SQL and the real plan in front of you rather than reasoning about the abstraction.