% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/map.R
\name{purrr_error_indexed}
\alias{purrr_error_indexed}
\title{Indexed errors (\code{purrr_error_indexed})}
\description{
The \code{purrr_error_indexed} class is thrown by \code{\link[=map]{map()}}, \code{\link[=map2]{map2()}}, \code{\link[=pmap]{pmap()}}, and friends.
It wraps errors thrown during the processing on individual elements with information about the location of the error.
}
\section{Structure}{
\code{purrr_error_indexed} has three important fields:
\itemize{
\item \code{location}: the location of the error as a single integer.
\item \code{name}: the name of the location as a string. If the element was not named, \code{name} will be \code{NULL}
\item \code{parent}: the original error thrown by \code{.f}.
}

Let's see this in action by capturing the generated condition from a very simple example:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{f <- function(x) \{
  rlang::abort("This is an error")
\} 

cnd <- rlang::catch_cnd(map(c(1, 4, 2), f))
class(cnd)
#> [1] "purrr_error_indexed" "rlang_error"         "error"              
#> [4] "condition"

cnd$location
#> [1] 1

cnd$name
#> NULL

print(cnd$parent, backtrace = FALSE)
#> <error/rlang_error>
#> Error in `.f()`:
#> ! This is an error
}\if{html}{\out{</div>}}

If the input vector is named, \code{name} will be non-\code{NULL}:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{cnd <- rlang::catch_cnd(map(c(a = 1, b = 4, c = 2), f))
cnd$name
#> [1] "a"
}\if{html}{\out{</div>}}
}

\section{Handling errors}{
(This section assumes that you're familiar with the basics of error handling in R, as described in \href{https://adv-r.hadley.nz/conditions.html}{Advanced R}.)

This error chaining is really useful when doing interactive data analysis, but it adds some extra complexity when handling errors with \code{tryCatch()} or \code{withCallingHandlers()}.
Let's see what happens by adding a custom class to the error thrown by \code{f()}:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{f <- function(x) \{
  rlang::abort("This is an error", class = "my_error")
\} 
map(c(1, 4, 2, 5, 3), f)
#> Error in `map()`:
#> i In index: 1.
#> Caused by error in `.f()`:
#> ! This is an error
}\if{html}{\out{</div>}}

This doesn't change the visual display, but you might be surprised if you try to catch this error with \code{tryCatch()} or \code{withCallingHandlers()}:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{tryCatch(
  map(c(1, 4, 2, 5, 3), f),
  my_error = function(err) \{
    # use NULL value if error
    NULL
  \}
)
#> Error in `map()`:
#> i In index: 1.
#> Caused by error in `.f()`:
#> ! This is an error

withCallingHandlers(
  map(c(1, 4, 2, 5, 3), f),
  my_error = function(err) \{
    # throw a more informative error
    abort("Wrapped error", parent = err)
  \}
)
#> Error in `map()`:
#> i In index: 1.
#> Caused by error in `.f()`:
#> ! This is an error
}\if{html}{\out{</div>}}

That's because, as described above, the error that \code{map()} throws will always have class \code{purrr_error_indexed}:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{tryCatch(
  map(c(1, 4, 2, 5, 3), f),
  purrr_error_indexed = function(err) \{
    print("Hello! I am now called :)")
  \}
)
#> [1] "Hello! I am now called :)"
}\if{html}{\out{</div>}}

In order to handle the error thrown by \code{f()}, you'll need to use \code{rlang::cnd_inherits()} on the parent error:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{tryCatch(
  map(c(1, 4, 2, 5, 3), f),
  purrr_error_indexed = function(err) \{
    if (rlang::cnd_inherits(err, "my_error")) \{
      NULL
    \} else \{
      rlang::cnd_signal(err)
    \}
  \}
)
#> NULL

withCallingHandlers(
  map(c(1, 4, 2, 5, 3), f),
  purrr_error_indexed = function(err) \{
    if (rlang::cnd_inherits(err, "my_error")) \{
      abort("Wrapped error", parent = err)
    \}
  \}
)
#> Error:
#> ! Wrapped error
#> Caused by error in `map()`:
#> i In index: 1.
#> Caused by error in `.f()`:
#> ! This is an error
}\if{html}{\out{</div>}}

(The \code{tryCatch()} approach is suboptimal because we're no longer just handling errors, but also rethrowing them.
The rethrown errors won't work correctly with (e.g.) \code{recover()} and \code{traceback()}, but we don't currently have a better approach.
In the future we expect to \href{https://github.com/r-lib/rlang/issues/1534}{enhance \code{try_fetch()}} to make this easier to do 100\% correctly).

Finally, if you just want to get rid of purrr's wrapper error, you can resignal the parent error:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{withCallingHandlers(
  map(c(1, 4, 2, 5, 3), f),
  purrr_error_indexed = function(err) \{
    rlang::cnd_signal(err$parent)
  \}
)
#> Error in `.f()`:
#> ! This is an error
}\if{html}{\out{</div>}}

Because we are resignalling an error, it's important to use \code{withCallingHandlers()} and not \code{tryCatch()} in order to preserve the full backtrace context.
That way \code{recover()}, \code{traceback()}, and related tools will continue to work correctly.
}

\keyword{internal}
