Here's a dummy function and data:
foo = function(X,Y) { if (any(Y==2)) stop("Y contains 2!") X*Y } DT = data.table(a=1:3, b=1:6) DT ab 1: 1 1 2: 2 2 3: 3 3 4: 1 4 5: 2 5 6: 3 6
Step by step:
> DT[, c := foo(a,b), by=a ] Error in foo(a, b) : Y contains 2!
Well, that by design. Good.
In addition, despite the error, column c added.
> DT abc 1: 1 1 1 2: 2 2 NA 3: 3 3 NA 4: 1 4 4 5: 2 5 NA 6: 3 6 NA
Only the first successful group was filled; he stopped in the second group. This is by design. At some point in the future, we could add transactions to data.table internally, such as SQL, so that if an error occurred, any changes could be discarded. In any case, you just need to know something.
To handle the error, you can use {} .
First try:
> DT[, c := { if (inherits(try(ans<-foo(a,b)),"try-error")) NA else ans }, by=a] Error in foo(a, b) : Y contains 2! Error in `[.data.table`(DT, , `:=`(c, { : Type of RHS ('logical') must match LHS ('integer'). To check and coerce would impact performance too much for the fastest cases. Either change the type of the target column, or coerce the RHS of := yourself (eg by using 1L instead of 1)
The error tells us what to do. Let force type RHS ( NA ) from logical to integer .
> DT[, c:= { if (inherits(try(ans<-foo(a,b)),"try-error")) NA_integer_ else ans }, by=a] Error in foo(a, b) : Y contains 2!
Better, the long mistake has disappeared. But why else is there a mistake from foo ? See DT for verification only.
> DT abc 1: 1 1 1 2: 2 2 NA 3: 3 3 9 4: 1 4 4 5: 2 5 NA 6: 3 6 18
Oh, thatβs how it worked. The third group is started, and the values ββ9 and 18 are displayed on lines 3 and 6. The silent ?try shown in the ?try window.
> DT[, c:= { if (inherits(try(ans<-foo(a,b),silent=TRUE),"try-error")) NA_integer_ else ans }, by=a] >