Only catch errors that you know how to handle. If you don't know how to handle it, it should propagate higher up the stack, even if it kills the execution of the program.
This implies that having a catch-all around your entire program is a bad idea. Doing so loses the stack trace; you no longer know where the exception was thrown from. I've had to debug programs that did this, and the first thing I did was comment out the catch all so a simple stack trace could tell me where to start looking.
In the compiler I'm writing right now, I do wrap the entire execution in a try-catch block, but the only errors I catch are ones I call "user_error". That represents an error in the input; I don't handle that kind of input on purpose, and providing it is user error, not compiler error. I don't catch the other kinds of exceptions I throw, which indicate what gcc calls "internal compiler error." It's much easier for me to figure out what I did wrong that way.
The language I use doesn't prohibit display/logging of full stack trace if you catch exceptions. Or, trivially, catch/log in production catch/rethrow in dev.
What about daemons? large batch programs? I, personally, would rather have them catch and alert(email, sms) unknown/unexpected exceptions continuing on with what they can rather than simply die.
That's assuming you can continue on. Daemons and batch programs are unusual in that every so often, there's a conceptual "wipe clean" and all prior state doesn't matter. These are situations in which you know how to handle an error.
The alternative, to continue on in an error state without knowing how it will effect execution, is worse.
If you get an error, but the error is within a closed subset of your program, you should not propagate the error upwards. Let's say you are sending data to another program on the same system. The other program could do many things, and could send answers you do know how to reply to. The error is in your function and in your function alone - you should simply exit the function without exiting the program. The range of errors are limited, and none of them are life threatening, but only your function knows that, the rest of the program is unaware of what the unknown error means.
Propagating errors upwards like you say breaks functionality encapsulation.
What you said does not contradict my statement: only catch errors you know how to handle. You presented a situation in which you did know how to handle the error.
But if you don't know how to handle it, you should still throw it up, even if it breaks functionality encapsulation. This will likely crash the application, but the source of the error will be easily traceable, and the underlying problem can be fixed.
The most obvious to me is when you know something should be one of a finite set of values, and its actual value is not in that set. In my compiler, I have to classify array accesses as either a row or a column access. After a certain point, if it's neither (unitialized), then it's a serious error, I can't continue, and I throw an exception. I have similar situations when I deduce the types of an expression. Since I perform transformations on code, I also expect to find certain variables at certain places - if I can't find it anywhere, then I throw an exception.
Some of these are exceptions that I can recover from in that while the compilation is broken, I can still continue to find more errors. Others are show stoppers. I encounter these kinds of errors every time I have to do any decision based on these properties, which is often.
This implies that having a catch-all around your entire program is a bad idea. Doing so loses the stack trace; you no longer know where the exception was thrown from. I've had to debug programs that did this, and the first thing I did was comment out the catch all so a simple stack trace could tell me where to start looking.
In the compiler I'm writing right now, I do wrap the entire execution in a try-catch block, but the only errors I catch are ones I call "user_error". That represents an error in the input; I don't handle that kind of input on purpose, and providing it is user error, not compiler error. I don't catch the other kinds of exceptions I throw, which indicate what gcc calls "internal compiler error." It's much easier for me to figure out what I did wrong that way.