Let's say you have a stop('top secret info') somewhere in your code that contains some sensitive information. Toggle between sanitized and unsanitized errors to see what error message is displayed to the user in each scenario:

Even if you're not using a stop() in your own code, you're probably relying on code that does. For example, see what happens when the input field below is blank (enter a number to see its normal behavior):

If you multiply your number by 100, you get:

In this case, the unsanitized error doesn't seem to reveal any sensitive information. However, in less trivial examples, the error message may contain things like the path to a file or names of databases. If you sanitize errors, you can rest assured that no sensitive information will ever be leaked through error messages. This can be especially useful in cases for which you did not foresee that a particular error could occur (maybe because the user entered a very strange input or a dependency failed).

What if you do want to sanitize most of your errors but, for a couple of cases, you actually want to use an error message to let the user know what went wrong? In that situation, keep options(shiny.sanitize.errors = TRUE) and instead of stop(e) (with e being either an error or a string), use stop(safeError(e)) to create your error messages. Wrapping your error in safeError() basically declares that it is safe for the user to see and therefore it doesn't need to be sanitized.

For example, if you have a stop(safeError('the user should see this no matter what') somewhere in your code, it doesn't matter whether or not you're sanitizing errors: the user will always see the same error message:

If you want to use safeError() to show an error that does not originate in your own code (but in code you rely on), it gets a tiny bit trickier. Because you are not throwing the error yourself, you'll first need to catch it using tryCatch(). Through this function, you can then rethrow it to safeError() as desired. Using the example from the 'Basic Usage' tab, here's what you'd need to have inside your renderText() function:

return(tryCatch(input$n * 100, error = function(e) stop(safeError(e))))

If you multiply your number by 100, you get:

Notice a discrepancy between the code used above and the one in the server.R code? Click here to learn more

This error hiding mechanism also applies to less common errors. For example, if you have a syntax error in your ui.R; or if your downloadHandler() function has a bug. Because these errors do not go through the websockets set up by Shiny, they are handled differently (they open up a new window that just displays the error message). Still, for our purposes, you can sanitize them in the exact same way as before. You can also use safeError().

Let's say you want to give your users the ability to download a dataset. But in the downloadHandler() function, you mispelled the name of the function that fetches the data (you wrote datasetInpute() instead of datasetInput()). Toggle between sanitized and unsanitized errors and then click on the 'Download' button to see what error message is displayed to the user in each scenario (you can also make it a safeError if you wish):