This is from a case I helped a customer with last Autumn. It was one of those kick yourself moments when I realised what the problem was and we even have a KB article about it. But it is relatively uncommon and you wouldn't necessarily come across the article by chance.
You're using out of process session state service service or SQL Server hosted session state for your application because you have more than one web server and you load balance between them. In this case it was the session state server service that the customer was using.
You find that sometime requests are behaving as if the sessions state you thought you had has suddenly vanished.
In an in-process session state configuration you would normally think this was down to an unexpected worker process or application restart but that's why you've used an out of process configuration, right?
In this case we tracked it down by doing a controlled test where we'd done a clean restart of the session state service and also both web servers. Then having made the requests that put the data into the session state we forced a fail over and took a memory dump of the session state service.
I then dumped out all the HttpContext objects (which had not yet been garbage collected and therefore acted as a record of recent requests to set or retrieve session state) in the session state service (which is basically implemented as a relatively simple web server) and saw the following:
HttpContext ReturnCode Verb RequestPath+QueryString
0x0d129748 200 PUT //LM/W3SVC/1446149547/ROOT(lKWiOOz3dH8k+H0JvweJgHNm3hI=)/z445nnecaiiqye55asxwtm55
0x0914b37c 200 PUT //LM/W3SVC/1446149547/Root(rFlg8p6U4SNNj7SSJTCgM5GI9h4=)/z445nnecaiiqye55asxwtm55
0x09142200 200 GET //LM/W3SVC/1446149547/Root(rFlg8p6U4SNNj7SSJTCgM5GI9h4=)/z445nnecaiiqye55asxwtm55
0x09140d18 200 PUT //LM/W3SVC/1446149547/Root(rFlg8p6U4SNNj7SSJTCgM5GI9h4=)/z445nnecaiiqye55asxwtm55
0x09137b9c 200 GET //LM/W3SVC/1446149547/Root(rFlg8p6U4SNNj7SSJTCgM5GI9h4=)/z445nnecaiiqye55asxwtm55
0x091365b0 200 PUT //LM/W3SVC/1446149547/Root(rFlg8p6U4SNNj7SSJTCgM5GI9h4=)/z445nnecaiiqye55asxwtm55
0x09135344 404 GET //LM/W3SVC/1446149547/Root(rFlg8p6U4SNNj7SSJTCgM5GI9h4=)/z445nnecaiiqye55asxwtm55
0x091340d8 200 GET //LM/W3SVC/1446149547/ROOT(lKWiOOz3dH8k+H0JvweJgHNm3hI=)/z445nnecaiiqye55asxwtm55
Notice the difference in case of "ROOT" and "Root". The metabase AppRoot attribute of the virtual directory is used for the internal application ID in ASP.NET applications and this in turn is used as the first part of the state item URL. The second part of the URL (in brackets) is the same application ID hashed and base 64 encoded using the machine key. This encoding is dependent on the case of the thing it is encoding. As a result, if the case of the AppRoot attribute is different on the two servers the state server service sees the request as coming from different servers.
As mentioned, this is already a known issue:
Usually it is having different site IDs in the metabase that catches people out but in this case it was simply the casing of the appRoot attribute.