(this question might be better suited for the User Experience site)
Change the error message to "We need you to log in again because you were inactive for more than XX minutes." Problem solved.
Let the user know how long they have exactly, because if they have to submit a complex form they need to be aware that they will need to collect whatever information they need and prepare whatever text they must input within a set time. Even better, monitor on which forms sessions tend to reset and use that information to figure out if you must support longer-lasting sessions.
Sometimes users might make a token expire before they even logged in as you pointed out. In that case, a formulation that is generic enough to cover both use cases will remove the need for you to try and test how the session looked like before it expired. You still need to address the confusion that such a message can cause for users who were not logged in before (their mental model might not accommodate the idea that individual forms expire rather than actual sessions).
You can do so by adding a "learn more" or "more details" link on your error message. Clicking that link can then display an additional paragraph that explains (succintly, and in very simple prose!) that Web login forms expire after XX minutes for security reasons, and the user was inactive for too long. You'll still need to ensure that additional text is visible to users without JS.
At this point you might as well implement your idea of serving a fresh CSRF token via AJAX when the user has been inactive for long enough...
Edit: some services directly display a timer indicating for how long the current page will be valid. You could go as far as implement such a timer on a standalone login page. This will at least prepare users to the idea that the page has expired / will expire, and can be especially useful if the page must be entirely refreshed when the timer expires. This being said, thee proper approach remains to never invalidate the existing login page.