> why do you think that this must happen on the front-end?
It must happen on both frontend and backend, because it's about their communication with each other. So that includes frontend.
> a) serve an error page, leaving that to the backend (at some point the backend must validate anyway)
> b) serve the regular front-end and react to the invalid state with error messages. there are libraries like zod that should make your job easier.
I mean, that is exactly what makes me so frustrated! Sorry, you are just giving a good example of what I'm complaining about. Both of those solutions are sub-optimal.
Here is how I'd implement that by hand if I would write something like nextjs/django:
1.) The frontend always sends a version in each of it's request (in the payload, the header, wherever)
2.) The backend compares that version against what it is expecting and compatible with. If it detects an outdated/incompatible version then there are two options: it is somehow possible to automatically fix it. For example because the used protocol has some mechanism and the developer uses that (such as default values for missing values) or because the developer has manually provided a migration for old versions.
3.) If it can be fixed, all good. If not, the backend sends a message back, saying that the request cannot be processed because the version is too old. The user can then decide to e.g. save their state elsewhere and reload, or just reload. Or do something completely different.
4.) Bonus: while we are at it, why don't have that fronted send regular requests to backend and ask if the version is still up-to-date (especially if it's the type of user that has their browser tab open forever). That would help to prevent data loss or other problems before they even occur, because the user gets an info and can refresh early.
Why should I implement all of that myself over and over again? Are you guys really thinking that this should not be handled, or at least made very easy, by typical weblibs/frontends such as nextss or django?