asLody/VirtualApp · error · java.lang.IllegalArgumentException

Exactly one of stageDir or stageCid stage must be set

Error message

Exactly one of stageDir or stageCid stage must be set

What it means

A session's backing storage must be identified exactly once: either a stageDir (directory on disk) or a stageCid (encrypted-container ID). open() checks on first preparation that stageDir is non-null (stageCid is handled by the caller's context); if stageDir is null it throws IllegalArgumentException('Exactly one of stageDir or stageCid stage must be set').

Solutions

  1. Pass a valid, writable stage directory (e.g. new File(VEnvironment.getPackageInstallerStageDir(), String.valueOf(sessionId))) to open().
  2. Provide exactly one of stageDir or stageCid — never both null (and avoid both set).
  3. Confirm the stage dir exists (mkdirs) and is accessible before open().

Example fix

// before
session.open(null, userId); // IllegalArgumentException

// after
File stageDir = new File(VEnvironment.getPackageInstallerStageDir(), String.valueOf(session.sessionId));
stageDir.mkdirs();
session.open(stageDir, userId);
Defensive patterns

Strategy: validation

Validate before calling

File stageDir = new File(VEnvironment.getPackageInstallerStageDir(), String.valueOf(sessionId));
if (stageDir == null || (!stageDir.exists() && !stageDir.mkdirs())) {
    throw new IOException("Cannot prepare stage dir: " + stageDir);
}
session.open(stageDir, userId);

Type guard

boolean hasValidStage(File stageDir) { return stageDir != null && (stageDir.isDirectory() || stageDir.mkdirs()); }

Try / catch

try {
    session.open(stageDir, userId);
} catch (IllegalArgumentException e) {
    if (String.valueOf(e.getMessage()).startsWith("Exactly one of stageDir")) {
        session.open(defaultStageDirFor(session.sessionId), userId);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling session.open(null, userId) on a first-time (unprepared) session; constructing PackageInstallerSession with a null stage dir and then opening it; opening a session twice where the first open never set mPrepared due to a null arg.

Common situations: Custom code paths that build sessions without VEnvironment.getPackageInstallerStageDir()-derived directories; copy-paste from AOSP variants where stageCid was used but VirtualApp expects a stageDir; refactors dropping the stageDir argument.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09). Data as JSON: /api/errors/526d73070dee9455. Report an issue: GitHub.

Appendix: source

Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java:481

            synchronized (mLock) {
                mPermissionsAccepted = true;
            }
            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
        } else {
            destroyInternal();
            dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
        }
    }

    public void open() throws IOException {
        if (mActiveCount.getAndIncrement() == 0) {
            mCallback.onSessionActiveChanged(this, true);
        }

        synchronized (mLock) {
            if (!mPrepared) {
                if (stageDir == null) {
                    throw new IllegalArgumentException(
                            "Exactly one of stageDir or stageCid stage must be set");
                }
                mPrepared = true;
                mCallback.onSessionPrepared(this);
            }
        }
    }


    public static String getCompleteMessage(Throwable t) {
        final StringBuilder builder = new StringBuilder();
        builder.append(t.getMessage());
        while ((t = t.getCause()) != null) {
            builder.append(": ").append(t.getMessage());
        }
        return builder.toString();
    }

View on GitHub (pinned to 666fefcb5d)