diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp
index eb6bb169ce..533797a657 100644
--- a/libraries/gpu/src/gpu/Texture_ktx.cpp
+++ b/libraries/gpu/src/gpu/Texture_ktx.cpp
@@ -252,7 +252,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
                 }
                 images.emplace_back(ktx::Image(imageOffset, (uint32_t)mip->getSize(), 0, cubeFaces));
             }
-            imageOffset += mip->getSize() + 4;
+            imageOffset += static_cast<uint32_t>(mip->getSize()) + 4;
         }
     }
 
diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp
index 45820b9351..d9b5ea4a62 100644
--- a/libraries/ktx/src/ktx/KTX.cpp
+++ b/libraries/ktx/src/ktx/KTX.cpp
@@ -12,6 +12,7 @@
 #include "KTX.h"
 
 #include <algorithm> //min max and more
+#include <QDebug>
 
 using namespace ktx;
 
@@ -90,6 +91,7 @@ size_t Header::evalPixelOrBlockSize() const {
             return 4;
         }
     }
+    qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat;
     throw std::runtime_error("Unknown format");
 }
 
@@ -119,7 +121,7 @@ ImageDescriptors Header::generateImageDescriptors() const {
     ImageDescriptors descriptors;
 
     uint32_t imageOffset = 0;
-    for (auto level = 0; level < numberOfMipmapLevels; ++level) {
+    for (uint32_t level = 0; level < numberOfMipmapLevels; ++level) {
         auto imageSize = static_cast<uint32_t>(evalImageSize(level));
         ImageHeader header {
             numberOfFaces == NUM_CUBEMAPFACES,
@@ -131,7 +133,7 @@ ImageDescriptors Header::generateImageDescriptors() const {
         imageOffset += imageSize + 4;
 
         ImageHeader::FaceOffsets offsets;
-        for (auto i = 0; i < numberOfFaces; ++i) {
+        for (uint32_t i = 0; i < numberOfFaces; ++i) {
             offsets.push_back(0);
         }
         descriptors.push_back(ImageDescriptor(header, offsets));
diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index 3e06142d8e..3d81dd51e9 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -38,6 +38,7 @@
 #include <Finally.h>
 #include <Profile.h>
 
+#include "NetworkLogging.h"
 #include "ModelNetworkingLogging.h"
 #include <Trace.h>
 #include <StatTracker.h>
@@ -345,14 +346,12 @@ void NetworkTexture::makeRequest() {
     // We special-handle ktx requests to run 2 concurrent requests right off the bat
     PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } });
 
-    if (!_ktxHeaderLoaded) {
+    if (!_ktxHeaderLoaded && !_highMipRequestFinished) {
         qDebug() << ">>> Making request to " << _url << " for header";
         _ktxHeaderRequest = ResourceManager::createResourceRequest(this, _activeUrl);
 
         if (!_ktxHeaderRequest) {
             //qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
-            ResourceCache::requestCompleted(_self);
-            finishedLoading(false);
             PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID));
             return;
         }
@@ -373,9 +372,14 @@ void NetworkTexture::makeRequest() {
         _bytesReceived = _bytesTotal = _bytes = 0;
 
         _ktxHeaderRequest->send();
+
+        startMipRangeRequest(NULL_MIP_LEVEL, NULL_MIP_LEVEL);
+    } else {
+        if (_lowestKnownPopulatedMip > 0) {
+            startMipRangeRequest(_lowestKnownPopulatedMip - 1, _lowestKnownPopulatedMip - 1);
+        }
     }
 
-    startMipRangeRequest(NULL_MIP_LEVEL, NULL_MIP_LEVEL);
 }
 
 void NetworkTexture::handleMipInterestCallback(uint16_t level) {
@@ -384,13 +388,24 @@ void NetworkTexture::handleMipInterestCallback(uint16_t level) {
 
 void NetworkTexture::handleMipInterestLevel(int level) {
     _lowestRequestedMipLevel = std::min(static_cast<uint16_t>(level), _lowestRequestedMipLevel);
-    if (!_ktxMipRequest) {
-        startRequestForNextMipLevel();
+    if (!_ktxMipRequest && _lowestKnownPopulatedMip > 0) {
+        //startRequestForNextMipLevel();
+        clearLoadPriority(this);
+        setLoadPriority(this, _lowestKnownPopulatedMip - 1);
+        ResourceCache::attemptRequest(_self);
     }
 }
 
 void NetworkTexture::startRequestForNextMipLevel() {
-    startMipRangeRequest(std::max(0, _lowestKnownPopulatedMip - 1), std::max(0, _lowestKnownPopulatedMip - 1));
+    if (_lowestKnownPopulatedMip == 0) {
+        qWarning(networking) << "Requesting next mip level but all have been fulfilled";
+        return;
+    }
+    if (_pending) {
+        return;
+    }
+
+    //startMipRangeRequest(std::max(0, _lowestKnownPopulatedMip - 1), std::max(0, _lowestKnownPopulatedMip - 1));
 }
 
 // Load mips in the range [low, high] (inclusive)
@@ -406,7 +421,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
     }
 
     _ktxMipRequest = ResourceManager::createResourceRequest(this, _activeUrl);
-    qDebug() << ">>> Making request to " << _url << " for " << low << " to " << high;
+    qDebug(networking) << ">>> Making request to " << _url << " for " << low << " to " << high;
 
     _ktxMipLevelRangeInFlight = { low, high };
     if (isHighMipRequest) {
@@ -437,7 +452,7 @@ void NetworkTexture::ktxHeaderRequestFinished() {
     if (_ktxHeaderRequest->getResult() == ResourceRequest::Success) {
         _ktxHeaderLoaded = true;
         _ktxHeaderData = _ktxHeaderRequest->getData();
-        maybeCreateKTX();
+        maybeHandleFinishedInitialLoad();
     } else {
         handleFailedRequest(_ktxHeaderRequest->getResult());
     }
@@ -455,15 +470,18 @@ void NetworkTexture::ktxMipRequestFinished() {
 
             _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first;
             
-            _textureSource->getGPUTexture()->assignStoredMip(_ktxMipLevelRangeInFlight.first,
-                _ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
-            //texture->assignStoredMip(level, image._imageSize, ktxData);
+            auto texture = _textureSource->getGPUTexture();
+            if (!texture) {
+                texture->assignStoredMip(_ktxMipLevelRangeInFlight.first,
+                    _ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
+            } else {
+                qWarning(networking) << "Trying to update mips but texture is null";
+            }
         } else {
             _highMipRequestFinished = true;
             _ktxHighMipData = _ktxMipRequest->getData();
-            maybeCreateKTX();
+            maybeHandleFinishedInitialLoad();
         }
-
     } else {
         handleFailedRequest(_ktxMipRequest->getResult());
     }
@@ -472,11 +490,13 @@ void NetworkTexture::ktxMipRequestFinished() {
 }
 
 // This is called when the header or top mips have been loaded
-void NetworkTexture::maybeCreateKTX() {
+void NetworkTexture::maybeHandleFinishedInitialLoad() {
     if (_headerRequestFinished && _highMipRequestFinished) {
         ResourceCache::requestCompleted(_self);
 
-        if (_ktxHeaderData.size() > 0 && _ktxHighMipData.size() > 0) {
+        if (_ktxHeaderData.size() == 0 || _ktxHighMipData.size() == 0) {
+            finishedLoading(false);
+        } else {
             // create ktx...
             auto header = reinterpret_cast<const ktx::Header*>(_ktxHeaderData.data());
 
@@ -490,6 +510,7 @@ void NetworkTexture::maybeCreateKTX() {
             auto kvSize = header->bytesOfKeyValueData;
             if (kvSize > _ktxHeaderData.size() - ktx::KTX_HEADER_SIZE) {
                 qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request";
+                finishedLoading(false);
                 return;
             }
 
@@ -505,23 +526,23 @@ void NetworkTexture::maybeCreateKTX() {
             std::string filename;
             if (found == keyValues.end()) {
                 qWarning("Source hash key not found, bailing");
-                filename = "test";
-                //return;
-
+                finishedLoading(false);
+                return;
             }
             else {
-                if (found->_value.size() < 16) {
-                    filename = _activeUrl.fileName().toStdString();
-                }
-                else {
+                if (found->_value.size() < 32) {
+                    qWarning("Invalid source hash key found, bailing");
+                    finishedLoading(false);
+                    return;
+                } else {
                     filename = std::string(reinterpret_cast<char*>(found->_value.data()), 32);
                 }
             }
 
             auto memKtx = ktx::KTX::createBare(*header, keyValues);
 
-            auto d = const_cast<uint8_t*>(memKtx->getStorage()->data());
-            ///memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size());
+            //auto d = const_cast<uint8_t*>(memKtx->getStorage()->data());
+            //memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size());
 
             auto textureCache = DependencyManager::get<TextureCache>();
 
@@ -531,7 +552,8 @@ void NetworkTexture::maybeCreateKTX() {
             KTXFilePointer file;
             auto& ktxCache = textureCache->_ktxCache;
             if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
-                qCWarning(modelnetworking) << _url << "file cache failed";
+                qCWarning(modelnetworking) << _url << " failed to write cache file";
+                finishedLoading(false);
                 return;
             }
             else {
@@ -581,36 +603,8 @@ void NetworkTexture::maybeCreateKTX() {
                     break;
                 }
             }
-            ResourceCache::requestCompleted(_self);
 
             setImage(texture, header->getPixelWidth(), header->getPixelHeight());
-
-            return;
-
-            /*
-            // Force load the next two levels
-            {
-                QTimer* timer = new QTimer();
-                connect(timer, &QTimer::timeout, this, [=]() {
-                    //startMipRangeRequest(level, level);
-                    startRequestForNextMipLevel();
-                });
-                timer->setSingleShot(true);
-                timer->setInterval(4000);
-                timer->start();
-            }
-
-            {
-                QTimer* timer = new QTimer();
-                connect(timer, &QTimer::timeout, this, [=]() {
-                    //startMipRangeRequest(level - 1, level - 1);
-                    startRequestForNextMipLevel();
-                });
-                timer->setSingleShot(true);
-                timer->setInterval(6000);
-                timer->start();
-            }
-            */
         }
     }
 }
diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h
index 30eb9d2d2e..3048f16eb8 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.h
+++ b/libraries/model-networking/src/model-networking/TextureCache.h
@@ -84,7 +84,7 @@ protected:
     void startRequestForNextMipLevel();
 
     void startMipRangeRequest(uint16_t low, uint16_t high);
-    void maybeCreateKTX();
+    void maybeHandleFinishedInitialLoad();
 
 private:
     friend class KTXReader;
@@ -92,15 +92,28 @@ private:
 
     image::TextureUsage::Type _type;
 
-    KTXFilePointer _file;
     static const uint16_t NULL_MIP_LEVEL;
+    struct KTXResourceState {
+        NOT_LOADED = 0,
+        LOADING_INITIAL_DATA,    // Loading KTX Header + Low Resolution Mips
+        WAITING_FOR_MIP_REQUEST, // Waiting for the gpu layer to report that it needs higher resolution mips
+        PENDING_MIP_REQUEST,     // We have added ourselves to the ResourceCache queue
+        REQUESTING_MIP           // We have a mip in flight
+    };
+
+    KTXResourceState _ktxResourceState{ NOT_LOADED };
+
+    KTXFilePointer _file;
+
     bool _sourceIsKTX { false };
     bool _ktxHeaderLoaded { false };
+    bool _highMipRequestFinished { false };
+
     std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
+
     ResourceRequest* _ktxHeaderRequest { nullptr };
     ResourceRequest* _ktxMipRequest { nullptr };
-    bool _headerRequestFinished{ false };
-    bool _highMipRequestFinished{ false };
+    bool _headerRequestFinished { false };
     uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL };
     uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL };
     QByteArray _ktxHeaderData;
diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp
index 038ee7fb53..6716b7473f 100644
--- a/libraries/networking/src/ResourceCache.cpp
+++ b/libraries/networking/src/ResourceCache.cpp
@@ -474,8 +474,15 @@ int ResourceCache::getLoadingRequestCount() {
 
 bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
     Q_ASSERT(!resource.isNull());
-    auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
 
+    if (resource->_pending) {
+        qWarning(networking) << "Attempted to request " << resource->getURL() << " but it was already pending";
+        return false;
+    }
+
+    resource->_pending = true;
+
+    auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
     if (_requestsActive >= _requestLimit) {
         // wait until a slot becomes available
         sharedItems->appendPendingRequest(resource);
@@ -490,6 +497,12 @@ bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) {
 
 void ResourceCache::requestCompleted(QWeakPointer<Resource> resource) {
     auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
+
+    auto sharedResource = resource.lock();
+    if (sharedResource) {
+        sharedResource->_pending = true;
+    }
+
     sharedItems->removeRequest(resource);
     --_requestsActive;
 
diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h
index e699c3d198..13162aac9d 100644
--- a/libraries/networking/src/ResourceCache.h
+++ b/libraries/networking/src/ResourceCache.h
@@ -424,6 +424,9 @@ protected slots:
 protected:
     virtual void init();
 
+    /// Called by ResourceCache to begin loading this Resource.
+    /// This method can be overriden to provide custom request functionality. If this is done,
+    /// downloadFinished and ResourceCache::requestCompleted must be called.
     virtual void makeRequest();
 
     /// Checks whether the resource is cacheable.
@@ -460,6 +463,8 @@ protected:
 
     int _requestID;
     ResourceRequest* _request{ nullptr };
+
+    bool _pending{ false };
     
 public slots:
     void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal);