Unfortunately most of the projects I've been on are of the "We want to replace old system A and make a new system B that also has features X, Y, Z" variety. What they want from the new system is usually okay, it's somewhat documented already, you've identified some stakeholders, you can show them prototypes, you can ask for clarifications and their testing validates the feature. Developing new code for genuinely new features is actually quite easy and fun.
The old system on the other hand is more like software archaeology, nobody really seems to have the specs - or maybe a spec 1.0 from 10 years ago that's got nothing to do with reality - and if you're replacing it it's probably because it's crap, uncommented code in an arcane language with poor frameworks and third party components. So you dig and keep digging and try to implement something similar without knowing what's a feature and what's a bug, who'll come yelling if you break something or features nobody told you about and you weren't aware anyone was using disappear.
I had a bit of an epiphany today at work when i finally found out how structure a major piece of the redo I'm working on and I've so far spent ~2 months digging through that code. From a similar job I was doing in another area I thought maybe 2-3 months total, now I'm guessing it'll be 6-12 because of all the rework I have to make and every apparently simple thing has exceptions and special cases. It's wasn't my bad estimation, it's that the conditions are entirely different. Like comparing travel speed for a walk in the park to chopping your way through a dense jungle.