MuntashirAkon/AppManager · error · IOException
ERROR_MSG (constant; invalid/unknown file handle for calling
Error message
ERROR_MSG (constant; invalid/unknown file handle for calling pid)
What it means
FileContainer.get(handle) looks up an OpenFile by handle for the calling PID. It throws IOException("Requested file was not opened!") when there is no handle table at all for the calling process (files.get(pid) == null), meaning this process never opened any file through this container.
Source
Thrown at libcore/io/src/main/java/io/github/muntashirakon/io/FileContainer.java:26
import androidx.annotation.NonNull;
import java.io.IOException;
// Copyright 2022 John "topjohnwu" Wu
class FileContainer {
private final static String ERROR_MSG = "Requested file was not opened!";
private int nextHandle = 0;
// pid -> handle -> holder
private final SparseArray<SparseArray<OpenFile>> files = new SparseArray<>();
@NonNull
synchronized OpenFile get(int handle) throws IOException {
int pid = Binder.getCallingPid();
SparseArray<OpenFile> pidFiles = files.get(pid);
if (pidFiles == null)
throw new IOException(ERROR_MSG);
OpenFile h = pidFiles.get(handle);
if (h == null)
throw new IOException(ERROR_MSG);
return h;
}
synchronized int put(OpenFile h) {
int pid = Binder.getCallingPid();
SparseArray<OpenFile> pidFiles = files.get(pid);
if (pidFiles == null) {
pidFiles = new SparseArray<>();
files.put(pid, pidFiles);
}
int handle = nextHandle++;
pidFiles.append(handle, h);
return handle;
}
View on GitHub (pinned to 0152f468fc)
Solutions
- Ensure put() is called (via the FileSystemManager open API) in the same process before calling get().
- Re-open the file to obtain a fresh handle after a process restart or crash.
- Verify handles are not shared across processes; handles are per-PID and not transferable.
Example fix
// before
OpenFile f = container.get(handle); // throws if pid has no table
// after
try {
OpenFile f = container.get(handle);
} catch (IOException e) {
handle = container.put(reopenFile());
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean known = lastPutPid == android.os.Process.myPid() && lastPutHandle >= 0;
Try / catch
try {
OpenFile f = container.get(handle);
} catch (IOException e) {
if ("Requested file was not opened!".equals(e.getMessage())) {
handle = container.put(openFresh());
}
} Prevention
- Only use handles returned by put() in the same process
- Re-open after process restarts
- Never cache handles across binder client restarts
When it happens
Trigger: Calling get(handle) from a process (Binder.getCallingPid()) that never registered any OpenFile via put() — e.g. a remote process requesting a handle it does not own, or calls made after the client process's table was cleared.
Common situations: IPC clients reusing a handle from a different process; the client process died and pidDied() purged its handles, then it retries; server restart losing in-memory handle tables.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Invalid userId
- Can't unparcel type " + actual.getName() + " in list of type
- IOException(ERROR_MSG)
- IOException(REMOTE_ERR_MSG, throwable)
- The IBinder provided is invalid
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/f3ac504d476e5fd8.
Report an issue: GitHub.