That's the difference between an "intentional bug" and an "unintentional bug".
The former is when you want the program to do X, and X itself is wrong. Sure, defending against this is rarely possible. The latter is in my experience far more common. When you want the program to do X, but you actually told it to do Y.
Haskell catches most of the latter cases.
One of the main reasons is the functional purity. Because return values are the only result of a function, and these values are type-checked against a specification, it is much harder to do the wrong thing.
For example, an imperative program will idiomatically have methods whose sole effect is mutating their arguments or the objects. Even with a type system -- if you just omit the effects, the compiler really has no way to know that you meant the effects to happen, and you will simply have a bug. A purely functional program will idiomatically use a different style. Instead of mutating arguments and objects, it will return a new value. If you forget to return a new value, the compiler will catch that.
Additionally, the types in Haskell are generic by default. The more generic the type of a function, the more restricted is what that function can do. The restrictions narrow the space of wrong things you can do.
Another interesting property of Haskell is where it chooses to be on the "restrictiveness+guarantess vs. powerful+unguaranteed" trade-off.
It seems many don't even notice that the other side of the "power" coin is "guarantees". The more powerful a construct is -- the less you can say about what it will do. In Haskell, the purity and generic types of functions are two things that heavily restrict code. But there are many other mechanisms to restrict rather than empower code. In many contexts, restrictiveness is considered a bad thing, but in Haskell, this restrictiveness is very useful for reasoning about code.
For example, the function of type: (forall a. a -> a) in Haskell can only be the identity function. It cannot print "hello world", and it cannot mutate variables. These restrictions are useful because we now can have useful laws. For example: id . f = f . id = f. And we can derive these useful laws from the type itself, without even looking at the code!
By helping us find the most restrictive sub-language that can express the solution, we rule out even more bugs.