XMLHttpRequest doesn't use promises, and the Fetch API treats all HTTP responses -- including 429 -- as success.
I think you have a problem with a library.
But yeah...one of the several reasons I much prefer Fetch API/polyfill to $.ajax.
the pseudo-code example of the grandparent seems to me to implement a) detecting the http code, b) throwing an exception and finally c) handling this except.
Exceptions being for "exceptional" circumstances is a popular misconception. Exceptions are for "an upper layer to handle". You can use them for any alternative values you wish to propagate to the upper layer.
So are return values :) The difference is that return value is for the next immediate layer; an exception is for some layer, but I don't know what.
IMO your HTTP layer should not be throwing exceptions based on status code. The layer above that should.
I would put it the other way around. The http layer should not decide that the layer immediately above it must be the one to handle all its errors. It should also be the one that defines the default (success) case and the error case, since those are defined by the HTTP protocol.