immich-app/immich · error · EOFException
EOFException
Error message
EOFException
What it means
In RemoteImagesImpl.kt's OkHttp onResponse callback, the response body is streamed into a native buffer. If source.read returns -1 (stream ended) before the expected length has been fully read, an EOFException is thrown — the HTTP response was truncated mid-body.
Solutions
- Retry the download — OkHttp/Call retries or an app-level retry with backoff usually succeeds on a stable connection.
- Check server and reverse-proxy timeout/buffering settings (e.g. nginx proxy_read_timeout) so large responses aren't truncated.
- Verify server health/logs for connection resets during the transfer.
- Consider range-based resumable downloads for large originals.
Example fix
// before
val bytes = downloadOnce(url)
// after
val bytes = runCatching { downloadOnce(url) }.getOrElse { e ->
if (e is EOFException) retryWithBackoff(3) { downloadOnce(url) } else throw e
} Defensive patterns
Strategy: retry
Try / catch
try {
downloadAndBuffer(response)
} catch (e: EOFException) {
retryWithBackoff(maxAttempts = 3) { redownload(url) }
} Prevention
- Build app-level retry with backoff for remote media downloads.
- Tune reverse-proxy timeouts for large image responses.
- Watch for server restarts; resume with range requests when possible.
When it happens
Trigger: Server closes the connection after sending fewer bytes than Content-Length promised; interrupted network transfer mid-download of the original image; proxy/load-balancer timeouts cutting the response short.
Common situations: Flaky mobile networks during full-quality remote image downloads; Immich server restarts or reverse-proxy (nginx) buffering timeouts; reading via wifi-to-cellular handoff.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- await response.text()
- errors.unable_to_upload_file
- Failed to fetch activation key
- Invalid image data
- Machine learning request to
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/eccf29b927cb5b0a.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImagesImpl.kt:477
}
val body = response.body
?: return onFailure(IOException("Empty response body")).also { onComplete() }
if (call.isCanceled()) {
onFailure(OperationCanceledException())
return onComplete()
}
body.source().use { source ->
val length = body.contentLength().toInt()
val buffer = NativeByteBuffer(if (length > 0) length else INITIAL_BUFFER_SIZE)
try {
if (length > 0) {
val wrapped = NativeBuffer.wrap(buffer.pointer, length)
while (wrapped.hasRemaining()) {
if (call.isCanceled()) throw OperationCanceledException()
if (source.read(wrapped) == -1) throw EOFException()
}
buffer.advance(length)
} else {
while (true) {
if (call.isCanceled()) throw OperationCanceledException()
val bytesRead = source.read(buffer.wrapRemaining())
if (bytesRead == -1) break
buffer.advance(bytesRead)
buffer.ensureHeadroom()
}
}
onSuccess(buffer, response.header("Content-Type"))
} catch (e: Exception) {
buffer.free()
onFailure(e)
}
onComplete()
}View on GitHub (pinned to e55ac299a4)