MuntashirAkon/AppManager · error · IOException

Could not write the whole resource (total = %d, read = %d)

Error message

Could not write the whole resource (total = %d, read = %d)

What it means

Thrown inside the write-side pipe in StorageManagerCompat.openProxyFileDescriptor when the bytes written through the FileDescriptor (currOffset) do not equal the size returned by callback.onGetSize(). It indicates the consumer wrote fewer bytes than the resource is supposed to contain.

Source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/compat/StorageManagerCompat.java:126

                } finally {
                    callback.onRelease();
                }
            });
            return pipe[0];
        } else if ((mode & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0) {
            // Writing requested i.e. we have to read from the target and write it to our side
            callback.mHandler.post(() -> {
                try (ParcelFileDescriptor.AutoCloseInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0])) {
                    long currOffset = 0;
                    byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
                    int size;
                    while ((size = is.read(buf)) != -1) {
                        callback.onWrite(currOffset, size, buf);
                        currOffset += size;
                    }
                    long totalSize = callback.onGetSize();
                    if (totalSize > 0 && currOffset != totalSize) {
                        throw new IOException(String.format(Locale.ROOT, "Could not write the whole resource (total = %d, read = %d)", totalSize, currOffset));
                    }
                } catch (IOException | ErrnoException e) {
                    Log.e(TAG, "Failed to write file.", e);
                    try {
                        pipe[0].closeWithError(e.getMessage());
                    } catch (IOException exc) {
                        Log.e(TAG, "Can't even close PFD with error.", exc);
                    }
                } finally {
                    callback.onRelease();
                }
            });
            return pipe[1];
        } else {
            // Should never happen.
            pipe[0].close();
            pipe[1].close();
            Log.e(TAG, "Mode " + mode + " is not supported.");

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Ensure onGetSize() returns the real size of the incoming data, or 0/negative if unknown so the check is skipped
  2. Check the source InputStream for early EOF and surface its errors instead of silently ending the loop
  3. Wrap the copy so an IOException on read propagates via closeWithError
  4. Recompute the size after the copy and compare before committing the output

Example fix

// before
long totalSize = callback.onGetSize();
if (totalSize > 0 && currOffset != totalSize) { throw ... }
// after
long totalSize = callback.onGetSize();
if (totalSize < 0) totalSize = currOffset; // unknown size: accept what was written
if (totalSize > 0 && currOffset != totalSize) {
    throw new IOException(String.format(Locale.ROOT, "Could not write the whole resource (total = %d, read = %d)", totalSize, currOffset));
}
Defensive patterns

Strategy: validation

Validate before calling

// skip the strict equality check when size is unknown
long size = callback.onGetSize();
if (size <= 0) { /* treat as streaming: accept any byte count */ }

Try / catch

try {
    // write through the descriptor
} catch (IOException e) {
    long written = getBytesWritten();
    long expected = callback.onGetSize();
    Log.e(TAG, "Wrote " + written + "/" + expected + " bytes");
    restartTransfer();
}

Prevention

When it happens

Trigger: Writing a proxied file where the writer's stream ends early (input InputStream hit EOF prematurely), onGetSize() reports an inflated size, or an upstream read error silently ended the copy loop.

Common situations: Copying a partially downloaded file into a proxied descriptor; size metadata from a DB/cache entry that doesn't match the actual data; interrupted transfers.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/e03e5d2d629978ab. Report an issue: GitHub.