WP_Error is a return value. Creating one has no effect on control flow, so a function that builds one and does not return it has done nothing at all — and the calling code carries on with whatever came next.
function save_thing( $data ) {
if ( empty( $data['sku'] ) ) {
new WP_Error( 'missing_sku', 'SKU required.' ); // does nothing
}
return wp_insert_post( $data ); // still runs
}
It is the oldest error-handling convention in the codebase and it predates exceptions being usable in PHP, which is why it is everywhere. In new code the pragmatic approach is to throw internally and translate to WP_Error only at the boundary where core or a hook expects one. The class also collects several errors under codes, which almost nothing takes advantage of.