Using the Chrome console and two simple test portlets, you can see the issue happening. After initial load of the portal page but before any interaction, we query for all the ViewStates. Since there are two portlets and 3 forms per portlet (1 that is from the portlet markup and two hidden ones that ICEfaces inserts), it returns 6 values, 3 for each portlet:
document.getElementsByName('javax.faces.ViewState');
[
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"-3978125222353783743:​1573083955214999241" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"-3978125222353783743:​1573083955214999241" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"-3978125222353783743:​1573083955214999241" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off">​
]
After clicking the "Update with Push" button, the console logs which updates are being applied:
...
[window] applied updates >>
..
update["javax.faces.ViewState"]: -3978125222353783743:1573083955214999241.... location3:1230
[window] applied updates >>
...
update["javax.faces.ViewState"]: -3978125222353783743:1573083955214999241.... location3:1230
[window] applied updates >>
...
update["javax.faces.ViewState"]: 7928353047340332639:-1008142066134303525.... location3:1230
Querying again for the ViewState values, you can see that all of the forms now have the ViewState of the second portlet:
document.getElementsByName('javax.faces.ViewState');
[
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off">​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off" style>​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off" style>​
,
<input type=​"hidden" name=​"javax.faces.ViewState" id=​"javax.faces.ViewState" value=​"7928353047340332639:​-1008142066134303525" autocomplete=​"off" style>​
Here are my notes on the issue to date:
1) The issue seems constrained to a problem with Push. I can run and interact with two separate portlets without seeing the issue. The exception only occurs after one or two Push renders are triggered.
2) The SessionExpiredException is slightly misleading. We add that exception handling to attempt to catch cases where a ViewExpiredException is thrown in a situation when the session has expired. In this case, it's not a session expiry but truly a ViewExpiredException.
3) I've narrowed it down to the fact to an update that comes back and updates the javax.faces.ViewState so that the returned value is applied to all views on the page (not just the portlet it actually belongs to. I've also constructed a test case that illustrates the ViewState "contamination" that occurs. In other words, when interacting with the first portlet and triggering a push, the updates for the 2nd portlet also include a ViewState value that gets applied back to the 1st portlet. Any subsequent interaction with that first portlet will throw a ViewExpiredException but that ViewState value doesn't exist for that view.