While
open3 does a lot (incl propagating exec errors to the parent), it's still a low level module. It's doesn't help you read from the child's STDOUT and its STDERR without combining them, a situation prone to deadlocks.
IPC::Run3 and
IPC::Run are higher-level solutions.