I agree with you that it would be better to only throw objects (and furthermore only objects that implements a certain interface). However, the compatibility issue makes it far from trivial to enforce that.
The best we can do without stopping functional pike code from working is to provide supporting functions that handle non-objects too (like describe_error), and to gradually convert the errors thrown by pike itself to objects. There's some progress in these areas in every release.