Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Barbara/error hiding #1156

Merged
merged 16 commits into from
Apr 18, 2016
Merged

Barbara/error hiding #1156

merged 16 commits into from
Apr 18, 2016

Conversation

bborgesr
Copy link
Contributor

@bborgesr bborgesr commented Apr 5, 2016

A PR to address this issue. I think the coding for this is more or less finished. Planning on testing it a bit more, but aside from that, this should be good to merge soon.

An overview:
By default, all errors are now sanitized automatically. This means that most error messages will be replaced with a generic error message: "An error has occurred. Check your logs or contact the app author for clarification." We can disable this feature and go back to the way things were up until now by adding options(shiny.sanitize.errors = FALSE). However, if we want to sanitize most errors but there is one or two particular errors that we think would be really useful for the user to see (and which don't leak any sensitive information), then we can use the new customStop() function instead of the regular stop() function (even if we keep the default of options(shiny.sanitize.errors = TRUE)).

Possible issues

  • This applies to all errors produced in a shiny app, including the trickier cases of downloadHandler() and ui.R. The aesthetics are still very different though -- these two open a new window to display the error, rather than producing an in-place, red error message. This can be something for us to prettify at some point in the future...
  • This also applies to errors inside runtime: shiny Rmd documents. However, for that case, we're still not completely safe because sensitive information may still leak through to the end user via warnings and/or messages. This is something we'll need to think about. [The silver lining here is that if a warning or message occurs inside of a reactive or a renderXXX function, they do not show up in the document, only in the R Markdown console.]

@jcheng5
Copy link
Member

jcheng5 commented Apr 12, 2016

The default behavior is to sanitize, even when running Shiny apps locally? That feels like going overboard. I can understand defaulting to sanitizing in Shiny Server.

@jcheng5
Copy link
Member

jcheng5 commented Apr 12, 2016

How attached are you to the function name customStop? :) Any other candidates?

error = function(cond) {
# Don't print shiny.silent.error (i.e. validation errors)
if (inherits(cond, "shiny.silent.error")) return()
if (isTRUE(getOption("show.error.messages"))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if show.error.messages is FALSE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I inherited this check from the shiny.R code (before I added to it): if (isTRUE(getOption("show.error.messages"))) printError(cond). show.error.messages is a general R error handling option: from my understanding, if it is FALSE, no errors (strictly speaking, nothing produced by stop) is printed. I don't think it's really important whether we keep this or not because I don't think this is a widely used option. It doesn't hurt though, and keeps things consistent.

@bborgesr
Copy link
Contributor Author

@jcheng5:

  1. Yes, the default behavior is to sanitize, even when running Shiny apps locally.
    So, this I think it a big point of contention between you and Winston and Tareef (I'm Switzerland on this!) Their argument is: once we agree that the default is to sanitize errors in Shiny Server (and possibly Connect), then it would be good to be consistent. I.e. it'd be good for app authors working on their apps locally to have the same set of default options there as they'll have once they deploy them. And it isn't all that much more work because in local development, you have the console logs right there (don't have to go fishing for them, like with Shiny Server). That said, I understand your point of view as well. Maybe something to go over on Friday with everyone and reach a consensus?
  2. Not particularly attached to customStop :) But I couldn't really think of a better name... Is there something in particular that you dislike about customStop? I feel that, in the context of the documentation, the name makes sense. Other possibilities (none of which I like better than customStop though): priorityStop, shinyStop, showStop, importantStop, safeStop, unsanitizedStop (this one is a mouthful!)

@bborgesr
Copy link
Contributor Author

Update:

  • changed customStop(error) to stop(safeError(error)) as discussed with Joe -- this (hopefully) makes the concept easier for users to understand.
  • safeError() now also works for downloadHandler errors. Bliss!
  • refactored the code in middleware.R to avoid unnecessary duplication of the code used in withLogErrors()

@bborgesr
Copy link
Contributor Author

@jcheng5 @wch Let's merge this?

cond <- structure(
list(message = error),
class = c("shiny.custom.error", errorClass, "error", "condition")
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was actually picturing more like this (not tested):

if (inherits(error, "character")) {
  error <- simpleError(error)
}
if (!inherits(error, "error")) {
  stop("The class of the `error` parameter must be either 'error' or 'character'")
}
if (!("shiny.custom.error" %in% class(error))
  class(error) <- c("shiny.custom.error", class(error))
error

I'd like to use simpleError to convert the error string to an error obj, as it relies less on the internal implementation details of errors. And for the case where error is an error obj already, we can leave it alone as much as possible and just add the one class name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that makes sense. I've changed to that, with a small difference: I don't think this check is necessary: if (!("shiny.custom.error" %in% class(error)). error will never have the class shiny.custom.error a priori -- we'll always have to add it (right?) Also, I added the user-provided errorClass to class(error).

@jcheng5
Copy link
Member

jcheng5 commented Apr 14, 2016

Looks great other than my one last comment!

stop("The class of the `error` parameter must be either 'error' or 'character'")
}
return(cond)
class(error) <- c("shiny.custom.error", errorClass, class(error))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't notice errorClass before--what's the intended usage of this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause I think it might make more sense to just say, if you want to provide a custom error class, just give us a custom error object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... Initially, I just took errorClass from stopWithCondition that has an argument just like that. I then thought it was worth keeping around to allow app authors to style their apps however they want (yes, we do give them the "shiny.custom.error" class, but maybe one class is not enough). I doubt this will be used a lot, but it seemed unobtrusive enough that it was worth keeping it around to give app authors more control over their errors.

@bborgesr
Copy link
Contributor Author

Final updates:

  • removed errorClass argument from the safeError function
  • changed sanitization default to FALSE (on local development)

@bborgesr bborgesr merged commit f3d4f9f into master Apr 18, 2016
@bborgesr bborgesr deleted the barbara/error-hiding branch April 18, 2016 00:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants