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
- Ensure onGetSize() returns the real size of the incoming data, or 0/negative if unknown so the check is skipped
- Check the source InputStream for early EOF and surface its errors instead of silently ending the loop
- Wrap the copy so an IOException on read propagates via closeWithError
- 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
- Return 0/negative from onGetSize when size unknown
- Verify source stream completeness before writing
- Persist progress for resumable transfers
- Compare checksums after copy
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
- Could not read the whole resource (total = %d, read = %d)
- Couldn't find any writable Obb dir
- Could not backup data
- Mode ${mode} is not supported.
- Unable to open output stream.
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/e03e5d2d629978ab.
Report an issue: GitHub.