One example is adopting a safer or more productive programming language for a new version. The Rust ecosystem has now reached a point where it's a viable replacement for a lot of things we would almost certainly have used C++ for a decade ago with Rust offering significant safety and productivity benefits. Rust is also now being used to replace tools for web developers where the incumbents were written in JavaScript and in this case the advantage is order(s) of magnitude performance improvements.
Another is when your platform evolves and forces the issue like the web plugins being replaced by new web standards that we were talking about before. Here you might not need to rewrite your entire application but you probably are forced to rewrite the affected parts and possibly significantly change the software architecture around them. A related example is if you previously wrote your application targeting a specific environment and now want to support multiple environments but the operating systems or frameworks or other dependencies follow very different conventions that impose some constraints on your software design.