1. Requirements change frequently while the code is being developed. (If we had detailed specs, we'd be constantly re-writing them.)
2. People ask for estimates before I've had enough time to completely understand the complexity of the problem.
3. Higher-priority projects intervene, and when I go back to the original project (sometimes months later), additional time is needed to figure out what I was doing when I was interrupted.
Fortunately, my management understands that estimates are always going to slip in this kind of chaotic development environment. If we absolutely need to hit a release deadline, we usually start pushing less-critical features/fixes off to the next release. (I work on enterprise software that's sold to large companies, which has release cycles measured in months.)