I'm going to study the bug a bit more, and put in some patch before the upcoming minor tag on Monday.
Looking at the history and some past discussions, it seems Tomas reported somewhat similar problem and Andres proposed a patch here https://www.postgresql.org/message-id/20140514155204.GE23943@awork2.anarazel.de which got committed via b23b0f5588d2e2. Not exactly the same issue, but related to relcache flush happening in index_open().
I wonder if we should just add a recheck logic in RelationGetIndexAttrBitmap() such that if rd_indexvalid is seen as 0 at the end, we go back and start again from RelationGetIndexList(). Or is there any code path that relies on finding the old information?
The following comment at the top of RelationGetIndexAttrBitmap() also seems like a problem to me. CIC works with lower strength lock and hence it can change the set of indexes even though caller is holding the RowExclusiveLock, no? The comment seems to suggest otherwise.
4748 * Caller had better hold at least RowExclusiveLock on the target relation
4749 * to ensure that it has a stable set of indexes. This also makes it safe
4750 * (deadlock-free) for us to take locks on the relation's indexes.
I've attached a revised patch based on these thoughts. It looks a bit more invasive than the earlier one-liner, but looks better to me.