So just to complete this thread...
I removed the add() or replace() call in my adapter's getItem() method and simply instantiate the new fragments to avoid the IllegalStateException, but was unable to determine a logical place to move the replace() call so that I could tag the fragments. This is unfortunate as using the tag would be the most reliable solution.
I tried accessing the fragments using the internal "android:switcher..." tag, but that doesn't seem to work - looking at the tag of my fragments, the tag is always null - so maybe they changed the internal behavior to no longer generate tags by default.
I have resorted to maintaining my own collection of fragment instances that I populate during the getItem() call and update during the adapter's destroyItem() call. I hope there are no surprises along the way here that will cause my collection to have instances that are different than what the ViewPager/adapter are storing.