Search code examples
rr-markdownknitrkablekableextra

kableExtra::column_spec() returns undefined control sequence when rendering notebooks in a loop with rmarkdown::render()


I use knitr in an R markdown document to create table in a pdf report. A column contains lengthy product description which I usually wrap. For some reason the latex compilation started returning an error.

[UPDATE] rendering it once works succesfully, but rendering the notebook a second time causes the error. My real use case is a a loop within which I render the same notebook several time for different product groups. Similar to the use case described in bookdown where a report is rendered "for each state of a country".

Reproducible example that fails to render a pdf document

File /tmp/notebook.Rmd

---
title: "Test document"
output: pdf_document
---

```{r setup}
library(dplyr)
```

```{r}
iris %>%
    knitr::kable(format="latex") %>%
    kableExtra::column_spec(2, width = "10em")
```

Compiling the file to a pdf document with the R command:

rmarkdown::render("notebook.Rmd")

[Update]: Run the render command a second time to see the error.

Returns the error

/usr/bin/pandoc +RTS -K512m -RTS notebook.knit.md --to latex --from markdown+autolink_bare_uris+tex_math_single_backslash --output notebook.tex --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/pagebreak.lua --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/latex-div.lua --self-contained --highlight-style tango --pdf-engine pdflatex --variable graphics --variable 'geometry:margin=1in'
[WARNING] Deprecated: --self-contained. use --embed-resources --standalone
! Undefined control sequence.
<argument> r|>{\raggedleft \arraybackslash
                          s                 }p{10em}|r|r|l
l.117 ...\raggedleft\arraybackslash}p{10em}|r|r|l}

Error: LaTeX failed to compile notebook.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips. See notebook.log for more info.

Rendering to html works fine

---
title: "Test document"
output: html_document
---

```{r setup}
library(dplyr)
```

```{r}
iris %>%
    knitr::kable(format="html") %>%
    kableExtra::column_spec(2, width = "10em")
```

This renders without an error.


Solution

  • It works for me in RStudio when I click Knit, but not when I run rmarkdown::render("notebook.Rmd") as you did. After some playing around to see what the difference is (specifically I asked for a latex_document instead of a pdf_document so I could see the tex code), I found that the Knit button adds a whole lot of extra dependencies that aren't there in the rmarkdown::render() call.

    I think I understand why this sometimes worked for you. kableExtra sets all the extra dependencies when it is loaded, but only if it is loaded during a knitr LaTeX run. So the first time you run it, it would work, but the second time, it was already loaded, so it didn't set those dependencies. They need to be set during the run, they won't carry over from the previous run.

    So a workaround is to unload kableExtra before calling rmarkdown::render(). That way it will be loaded during the processing of your document, and things should be fine. Do this by

    unloadNamespace("kableExtra")
    rmarkdown::render("notebook.Rmd")
    

    The unloadNamespace("kableExtra") line can also be put into the document itself before the first use of kableExtra, e.g.

    ---
    title: "Test document"
    output: pdf_document
    ---
    
    ```{r setup}
    library(dplyr)
    unloadNamespace("kableExtra")
    ```
    
    ```{r}
    iris %>%
        knitr::kable(format="latex") %>%
        kableExtra::column_spec(2, width = "10em")
    ```