There are many ways that programs can handle errors at runtime. The excellent book Exercises in Programming Style proposes an interesting categorization of common error handling patterns. Fascinatingly, the programming language that you work in often actively encourages one particular error handling pattern over another.
In this style, a function that receives a bad input or encounters an error always returns a sensible result to its caller, silently reinterpreting the error to a valid value. Such a function will never crash the program but may produce unexpected results in the presence of bad inputs or errors.
Languages whose standard libraries and syntax regularly reinterpret errors and questionable input make it difficult to write programs that are not in this style.
Environments that encourage this style:
Developers that wish to use a more Fail Fast style of error handling (see below) but are forced to write in one of these languages may use special validation and linting tools to look for errors in the program text before they can be reinterpreted.
In this style, a function that receives a bad input or encounters an error refuses to continue, returning an error back to its caller.
Exercises in Programming Style makes the additional distinction that functions in some programs try to handle errors immediately at their point of detection no matter what (“Tantrum”), whereas functions in other programs prefer to bubble up errors to callers until a caller with enough context is reached that decides to actually handle the error (“Passive Aggressive”).
Programs in the Tantrum substyle have lots of error handling code scattered throughout the program text, whereas programs in the Passive Aggressive substyle tend to consolidate most error handling code in top-level functions and let lower-level code just bubble up errors.
Languages that have built-in exceptions make it easy to implement programs in the Passive Aggressive substyle.
Environments that encourage this style:
More comprehensively discusses considerations and specific implementation techniques for writing code that is robust in the presence of errors.