bumptech/glide · error · IOException

Failed to read all expected data, expected: {contentLength},

Error message

Failed to read all expected data, expected: {contentLength}, but read: {readSoFar}

What it means

Thrown by ContentLengthInputStream.checkReadSoFarOrThrow when the underlying stream returns end-of-stream (-1) but fewer bytes have been read than the Content-Length header declared. ContentLengthInputStream wraps an InputStream and verifies the byte count to catch truncated/corrupt network responses that would otherwise silently produce partial images.

Source

Thrown at library/src/main/java/com/bumptech/glide/util/ContentLengthInputStream.java:78

    checkReadSoFarOrThrow(value >= 0 ? 1 : -1);
    return value;
  }

  @Override
  public int read(byte[] buffer) throws IOException {
    return read(buffer, 0 /*byteOffset*/, buffer.length /*byteCount*/);
  }

  @Override
  public synchronized int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
    return checkReadSoFarOrThrow(super.read(buffer, byteOffset, byteCount));
  }

  private int checkReadSoFarOrThrow(int read) throws IOException {
    if (read >= 0) {
      readSoFar += read;
    } else if (contentLength - readSoFar > 0) {
      throw new IOException(
          "Failed to read all expected data"
              + ", expected: "
              + contentLength
              + ", but read: "
              + readSoFar);
    }
    return read;
  }
}

View on GitHub (pinned to eb14a895d8)

Solutions

  1. Add .error(fallbackDrawable) so the load degrades gracefully on truncation
  2. Retry the load with RequestBuilder.listener logging or a built-in retry via .thumbnail()/error(RequestBuilder)
  3. Investigate server/CDN: ensure Content-Length matches the actual body and that compression headers are consistent
  4. If using a custom OkHttpUrlLoader, configure OkHttp retries/timeouts and disable broken intermediate proxies

Example fix

// before
Glide.with(ctx).load(url).into(imageView) // crashes on truncated response

// after
Glide.with(ctx)
  .load(url)
  .error(R.drawable.fallback)
  .listener(object : RequestListener<Drawable> {
    override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
        Log.w(TAG, "Image load failed/truncated", e)
        return false
    }
    override fun onResourceReady(...) = false
  })
  .into(imageView)
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot validate network truncation locally; rely on .error(fallback) + a listener.
// Ensure server returns correct Content-Length and disable broken proxies.

Try / catch

Glide.with(ctx)
  .load(url)
  .error(R.drawable.fallback)
  .listener(loggingListener)
  .into(imageView)
// Where loggingListener.onLoadFailed logs the GlideException root causes
// (truncation appears as 'Failed to read all expected data...').

Prevention

When it happens

Trigger: Any Glide network load (http/https URL model) where the server closes the connection before sending all the bytes advertised in Content-Length: proxy truncation, flaky mobile networks, server-side streaming bugs, or a misconfigured Content-Length header larger than the actual body.

Common situations: Spotty cellular/Wi-Fi dropping mid-download; CDN/proxy cache serving a truncated object; backend setting Content-Length incorrectly (e.g. with chunked encoding); server compression (gzip) without updating Content-Length.

Related errors


AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14). Data as JSON: /api/errors/b22da31f24bfcbdc. Report an issue: GitHub.