You can also use enums, as shown in the post. You don't need trait objects.
EDIT 1
> without needing to use boxed trait objects [...] `anyhow`
It's my understanding that anyhow uses trait objects. The first sentence of its document says "This library provides anyhow::Error, a trait object based error type"
EDIT 1 END
> which have nice downcasting API
I'm not a fan of downcasting when not _absolutely_ necessary.
See my sibling comment about SNAFU for an alternate that allows keeping different errors separate while unifying them.