Yep. This surprised me as well but it is all there in black and white on the MDM Article for the <img> element.

I've always just plonked a onerror() handler on my image elements when I thought they needed it but it turns out that it doesn't fire in all erroneous circumstances. In fact, there is no way to write robust code that handles user-supplied images by handling events.
For instance, the following does not work if the src is a data url that does not decode properly.
// this does not work
function createImageFromSrc(src) {
const image = new Image()
image.onload = () => {
console.log("Image loaded - happy days")
doSomethingWithTheImage(image)
}
image.onerror = () => {
console.log("Image failed")
showAnErrorToTheUser()
}
image.src = src
}
This is a problem if, for instance, you want to support drag and drop or user-selected files. If the user selects a non-image file then neither onload or onerror will fire and your application will be in a weird state.
The solution if you need to dynamically create images is to use the image.decode() method which returns a promise which will be rejected if the image decoding fails for any reason.
// this is the way
function createImageFromSrc(src) {
const image = new Image()
image.src = src
image.decode().then(()=>{
console.log("Image loaded just as I promised")
doSomethingWithTheImage(image)
})
.catch((decodeError)=>{
console.log("Sorry Dave, I could not decode this image:", decodeError)
showAnErrorToTheUser()
})
.finally(()=>{
console.log("This happens either way")
})
}
Hopefully this helps somebody avoid the 45 minutes it took me to figure out what was going wrong in my code.