An error denotes a programming error.
The Prelude function
error represents an error with a message,
undefined represents an error with a standard message.
For a Haskell program, an
undefined value cannot be distinguished from an infinite loop,
let x=x+1 in x :: Int. Almost not.
So error and undefined value are somehow synonyms in Haskell.
Since Haskell is non-strict,
the occurence of an error within an expression is not necessarily an error,
if the erroneous value is ignored somewhere, e.g.
False && undefined.
However, if an expression finally evaluates to bottom or hangs in an infinite loop, then this is definitely a programming error.
Consider for instance
fromJust x or
fromMaybe (error "I know for sure, that x is Just, because ...") x.
If the user sees according errors, then something is wrong which only the programmer can repair.
These are really errors by the programmer and cannot be the final result in a correct program.
Thus there is (almost) no way to recover from an error, at least no recommended one.
However, you might have programmed a server which shall also keep running,
if some service crashes due to a programming error.
Or you want to quit a buggy program with a message like:
"The impossible happened, a program error occured. Please send an e-mail with the following stack trace to the developer."
The possibility to catch such errors in the
IO monad is really tempting for abuse.
So please think twice before you want to catch (and hide) an error,
whether the thing you want to handle is actually an exception.