Sync and async decoders share the same code; async decoder errors on unexpected end of stream