Why isn't it possible to cast to a timestamp in an index in PostgreSQL?
Casts from text to timestamp without time zone are handled by calling the type input function timestamp_in, which is STABLE.

The reason is that timestamp_in supports some other formats too:

SELECT 'now'::timestamp;

         timestamp          
----------------------------
 2019-10-09 09:53:32.026673
(1 row)


If you know that your input is always an ISO timestamp and this cannot happen, define your own conversion function:

CREATE FUNCTION text2ts(text) RETURNS timestamp without time zone
   LANGUAGE sql IMMUTABLE AS
$$SELECT CASE WHEN $1 ~ '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$'
            THEN CAST($1 AS timestamp without time zone)
       END$$;


You can use that in your queries and indexes.

If you lack paranoia and are sure of your data quality, you can omit the test. That will improve performance, but you risk index corruption if somebody sneaks something like now into the data.