asLody/VirtualApp · error · PackageManagerException
INSTALL_FAILED_INVALID_APK
INSTALL_FAILED_INVALID_APK
Error message
No packages staged
What it means
validateInstallLocked lists the resolved stage directory and throws PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged") when the directory is empty or unlistable. An install session must contain at least one staged APK file before it can be validated and installed.
Solutions
- Write the APK into the session via openWrite/writeStream (and commit the stream) before calling commit().
- Check the return of stream commit and verify the staged file exists and is non-empty before sealing.
- Catch IOException during streaming and abort/recreate the session instead of proceeding to commit.
- Verify sufficient storage space and readable stage directory.
Example fix
// before
PackageInstallerSession session = ...;
session.commit(statusReceiver); // nothing staged
// after
try (OutputStream out = session.openWrite("base", 0, apk.length())) {
out.write(bytes);
session.commitStream(out);
}
session.seal();
session.commit(statusReceiver); Defensive patterns
Strategy: validation
Validate before calling
File stageDir = session.getStageDir();
File[] files = stageDir != null ? stageDir.listFiles() : null;
if (files == null || files.length == 0) {
throw new IllegalStateException("No APK staged; write the APK before commit");
} Try / catch
try {
session.commit(statusReceiver);
} catch (PackageManagerException e) {
if (e.error == INSTALL_FAILED_INVALID_APK) {
Log.e(TAG, "Nothing staged: " + e.getMessage());
restartInstallFlow(apkFile);
}
} Prevention
- Always stream and commit the APK before seal/commit.
- Verify staged file size matches the source APK size.
- Handle IOException during streaming by aborting the session, not continuing.
- Check free disk space before starting an install.
When it happens
Trigger: Calling commit() on a session where no APK was ever written into the stage dir; writeStream failed silently; the stage dir path resolves to a nonexistent/non-listable directory (listFiles() == null).
Common situations: Forgetting to stream the APK before commit; passing an empty/closed InputStream so zero bytes were written; disk-full or IO error during streaming that left the stage dir empty; wrong stage dir due to resolveStageDir issues.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- accountType is null
- INSTALL_FAILED_INTERNAL_ERROR
- Invalid userId
- Unable to create application
- Unable to start receiver
AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09).
Data as JSON: /api/errors/03513d2254660483.
Report an issue: GitHub.
Appendix: source
Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java:189
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
};
}
private void validateInstallLocked() throws PackageManagerException {
mResolvedBaseFile = null;
mResolvedStagedFiles.clear();
File[] addedFiles = this.mResolvedStageDir.listFiles();
if (addedFiles == null || addedFiles.length == 0) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
}
for (File addedFile : addedFiles) {
if (!addedFile.isDirectory()) {
final String targetName = "base.apk";
final File targetFile = new File(mResolvedStageDir, targetName);
if (!addedFile.equals(targetFile)) {
addedFile.renameTo(targetFile);
}
mResolvedBaseFile = targetFile;
mResolvedStagedFiles.add(targetFile);
}
}
if (mResolvedBaseFile == null) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
}
}
View on GitHub (pinned to 666fefcb5d)