MuntashirAkon/AppManager · error · JSONException

Selected APK splits are missing.

Error message

Selected APK splits are missing.

What it means

ApkQueueItem.validateForReplay() requires mSelectedSplits (the chosen split APKs of a split/APK-suite install) to be non-null and non-empty when mInstallExisting is false. A split APK cannot be installed without knowing which splits to include, so a JSONException is thrown.

Source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/ApkQueueItem.java:238

        mOriginatingUri = originatingUri != null ? Uri.parse(originatingUri) : null;
        JSONObject apkSource = jsonObject.optJSONObject("apk_source");
        mApkSource = apkSource != null ? ApkSource.DESERIALIZER.deserialize(apkSource) : null;
        JSONObject installerOptions = jsonObject.optJSONObject("installer_options");
        mInstallerOptions = installerOptions != null ? InstallerOptions.DESERIALIZER.deserialize(installerOptions) : null;
        mSelectedSplits = JSONUtils.getArray(jsonObject.optJSONArray("selected_splits"));
    }

    public void validateForReplay() throws JSONException {
        if (mInstallExisting) {
            if (TextUtils.isEmpty(mPackageName)) {
                throw new JSONException("Package name is missing.");
            }
        } else {
            if (mApkSource == null) {
                throw new JSONException("APK source is missing.");
            }
            if (mSelectedSplits == null || mSelectedSplits.isEmpty()) {
                throw new JSONException("Selected APK splits are missing.");
            }
        }
        if (mInstallerOptions != null) {
            setInstallerOptions(InstallerOptions.resolveEffectiveOptions(mInstallerOptions,
                    mPackageName, mTestOnly));
        }
    }

    @NonNull
    @Override
    public JSONObject serializeToJson() throws JSONException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("op_id", mOperationId);
        jsonObject.put("package_name", mPackageName);
        jsonObject.put("app_label", mAppLabel);
        jsonObject.put("install_existing", mInstallExisting);
        jsonObject.put("test_only", mTestOnly);
        jsonObject.put("originating_package", mOriginatingPackage);

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Persist/populate mSelectedSplits (selected_splits in JSON) with at least the base split before replay
  2. For non-split packages, include the base entry id as the single selected split
  3. Validate split selection in the UI (require at least the base split) before creating the queue item
  4. Catch JSONException around getExecutableIntent and re-prompt the user to choose splits

Example fix

// before
JSONObject obj = new JSONObject(json); // selected_splits absent
ApkQueueItem item = new ApkQueueItem(obj);
item.getExecutableIntent(context); // throws
// after
if (obj.optJSONArray("selected_splits") == null) {
    JSONArray splits = new JSONArray();
    splits.put("base");
    obj.put("selected_splits", splits);
}
ApkQueueItem item = new ApkQueueItem(obj);
item.getExecutableIntent(context);
Defensive patterns

Strategy: validation

Validate before calling

if (!item.isInstallExisting() && (item.getSelectedSplits() == null || item.getSelectedSplits().isEmpty())) {
    throw new IllegalStateException("Select at least the base split before installing.");
}

Type guard

boolean hasSplits(ApkQueueItem item) {
    return item.isInstallExisting()
        || (item.getSelectedSplits() != null && !item.getSelectedSplits().isEmpty());
}

Try / catch

try {
    Intent i = item.getExecutableIntent(context);
} catch (JSONException e) {
    if (e.getMessage().contains("splits")) {
        openSplitSelectionScreen();
    }
}

Prevention

When it happens

Trigger: Replaying a queue item whose apkFile is a split APK suite but mSelectedSplits is null or empty — e.g. the selected_splits array was never saved in the JSON, or the user deselected all splits before queuing.

Common situations: Deserializing a saved install session missing the selected_splits key; programmatically building an ApkQueueItem for a split APK without calling the split-selection API; a UI flow that allowed confirming an install with zero splits checked.

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 MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/1ae7c53013964e5c. Report an issue: GitHub.