bli
bli

Reputation: 8194

Get error messages from R displayed as they natively appear in an R session using knitr

I would like to build an html document using Rmarkdown in which error messages from R can be displayed as they do natively appear in an R interactive session.

This question is similar, but doesn't have the requirement that error messages appear exactly as in an interactive session: I tried using error=TRUE for a given chunk, at the error gets prefixed with Error in eval(expr, envir, enclos)::

With the following chunk:

```{r, error=TRUE}
notexistingvariable
```

I expect:

Error: object 'notexistingvariable' not found

I get:

Error in eval(expr, envir, enclos): object 'notexistingvariable' not found

I tried adding the results="asis" option, but this has no effect here. I think this only applies to non-error output.


Attempt at using wrap.error

As suggested in the answers, I tried to set a custom wrap.error function.

test.Rmd:

---
title: "test"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)

wrap.error <- function(x, options) {
  # x is an error object, with components "call" and "message".  Ignore
  # the call, but wrap the result like code:
  paste0("```\n## Error: ", x$message, "\n```")
}
```

```{r, error=TRUE}
notexistingvariable
```

Conversion to html:

$ R -e "rmarkdown::render('test.Rmd',output_file='test.html')"

R version 3.5.1 (2018-07-02) -- "Feather Spray"
Copyright (C) 2018 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> rmarkdown::render('test.Rmd',output_file='test.html')


processing file: test.Rmd
  |................                                                 |  25%
  ordinary text without R code

  |................................                                 |  50%
label: setup (with options) 
List of 1
 $ include: logi FALSE

  |.................................................                |  75%
  ordinary text without R code

  |.................................................................| 100%
label: unnamed-chunk-1 (with options) 
List of 1
 $ error: logi TRUE


output file: test.knit.md

/usr/bin/pandoc +RTS -K512m -RTS test.utf8.md --to html4 --from markdown+autolink_bare_uris+ascii_identifiers+tex_math_single_backslash --output test.html --smart --email-obfuscation none --self-contained --standalone --section-divs --template /home/bli/R/x86_64-pc-linux-gnu-library/3.5/rmarkdown/rmd/h/default.html --no-highlight --variable highlightjs=1 --variable 'theme:bootstrap' --include-in-header /tmp/RtmpAoBtc7/rmarkdown-str53186fa5c04d.html --mathjax --variable 'mathjax-url:https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' 

Output created: test.html
> 
> 

The test.html file looks as follows:

html rendering by firefox


Using wrap.simpleError, as the updated answer now proposes, works.

Upvotes: 1

Views: 756

Answers (1)

user2554330
user2554330

Reputation: 44977

(Updated to reflect R 3.5.x changes)

You can set custom renderers for the output (see vignette("knit_print")), but I think they are not called when an error occurs. The generic wrap() function is called in that case. knitr defines a wrap.error() method, and prior to R 3.5.0, that could be overridden by a user. However, in the latest release of R, methods defined in a package are chosen in preference to those defined by the user, so it no longer works.

However, there is still a solution for some errors. For the example in the question, the error object that is created has class c("simpleError", "error", "condition"), and knitr doesn't define a wrap.simpleError() method. You can define one, and override its handling.

You do it like this:

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)

wrap.simpleError <- function(x, options) {
  # x is an error object, with components "call" and "message".  Ignore
  # the call, but wrap the result like code:
  paste0("```\n## Error: ", x$message, "\n```")
}
```

```{r, error=TRUE}
notexistingvariable
```

This displays the result like this: enter image description here

There's also an output hook to handle errors: see https://yihui.name/knitr/hooks/. However, it seems to be called after wrap.error, when the message is already formed. You could edit that message to delete the parts you don't want using code like this:

```{r}   
knitr::knit_hooks$set(error = function(x, options) {
  paste0("```\n", 
         sub(" in eval(expr, envir, enclos)", "", x, fixed = TRUE),
         "\n```")
})
```e

This may be more robust than the wrap.simpleError approach, which would stop working if knitr ever defined a wrap.simpleError method like that. It will also handle all errors, not just "simpleError" ones. It has the disadvantage that it is probably harder to customize it to handle different types of errors, and might not work in different locales where "Error in" is translated to some other language.

Upvotes: 4

Related Questions