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

  1. Write the APK into the session via openWrite/writeStream (and commit the stream) before calling commit().
  2. Check the return of stream commit and verify the staged file exists and is non-empty before sealing.
  3. Catch IOException during streaming and abort/recreate the session instead of proceeding to commit.
  4. 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

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


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)