The ASP.Net ReportViewer relies on ASP.Net session state to store critical data that can’t always be easily regenerated.  In local mode, it stores the report snapshot, which contains a compiled form of the report definition, some or all of the data used in the report, and some report state information such as which toggles have been expanded.  In server mode, depending on your configuration, session state may be used to store connection information to the report server.  The report viewer stores data in session state when the ASPX page is executing and retrieves it during future postbacks or from the report viewer’s HTTP handler when rendering the report asynchronously, retrieving report images, exporting the report, or printing.

The report viewer will throw an AspNetSessionExpiredException when information it previously placed in session is not available during a postback or HTTP handler operation.  The exception message is "ASP.NET session has expired".  But this can be misleading.  Fundamentally, the exception means that the expected data wasn’t in session state.  But this can be for a number of different reasons:

1. Your session really did expire
The report viewer will connect to its HTTP handler one minute prior to session expiring as long as the web page is still being displayed in the browser.  This keeps session from expiring while the report is still being viewed.  It tends to work well, but it isn’t a guarantee.  The web server may be under load or the connection may not be reliable.  If the user has been inactive for a long time and this "ping" does fail, the session will expire and future requests will fail with this exception.  In this situation, there generally isn’t much a user can do other than refresh the page to start report processing over again.

2. The session isn’t available to the server handling the request
I often see session state configured incorrectly when load balancing the web front end across multiple machines or a web garden.  If your load balancing doesn’t have client affinity, you’ll need to make sure that session state is shared across all nodes.  ASP.Net session defaults to inproc mode, meaning that it is stored in memory in a single process.  A separate process in a web garden or a separate machine handling a request to render the report will have its own instance of session state that does not contain the information the report viewer stored while executing the page.  This tends to manifest as a seemingly random failure - some images or charts will fail to load or the report will fail to render non-deterministically.  The requests that get routed to the process that handled the original ASPX request succeed but requests routed elsewhere fail.  The solution to this problem is to use a session state mode that can be shared by all nodes in the farm.

3. Cookies are disabled on the client
ASP.Net keeps track of a session with an HTTP cookie.  If a client has cookies disabled, postbacks or requests to the report viewer HTTP handler will not load the existing session, resulting in this exception.  In this case, you can turn on cookieless session mode.  ASP.Net will redirect the first request to the ASPX page to a URL that contains a session identifier rather than storing the identifier in a cookie.