{"record":{"id":"bac9050de610ea64","repo":"MuntashirAkon/AppManager","slug":"package-name-is-missing","errorCode":null,"errorMessage":"Package name is missing.","messagePattern":"Package name is missing\\.","errorType":"validation","errorClass":"JSONException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/ApkQueueItem.java","lineNumber":231,"sourceCode":"        mOperationId = !TextUtils.isEmpty(operationId) ? operationId : UUID.randomUUID().toString();\n        mPackageName = JSONUtils.optString(jsonObject, \"package_name\", null);\n        mAppLabel = JSONUtils.optString(jsonObject, \"app_label\", null);\n        mInstallExisting = jsonObject.optBoolean(\"install_existing\", false);\n        mTestOnly = jsonObject.optBoolean(\"test_only\", false);\n        mOriginatingPackage = JSONUtils.optString(jsonObject, \"originating_package\", null);\n        String originatingUri = JSONUtils.optString(jsonObject, \"originating_uri\", null);\n        mOriginatingUri = originatingUri != null ? Uri.parse(originatingUri) : null;\n        JSONObject apkSource = jsonObject.optJSONObject(\"apk_source\");\n        mApkSource = apkSource != null ? ApkSource.DESERIALIZER.deserialize(apkSource) : null;\n        JSONObject installerOptions = jsonObject.optJSONObject(\"installer_options\");\n        mInstallerOptions = installerOptions != null ? InstallerOptions.DESERIALIZER.deserialize(installerOptions) : null;\n        mSelectedSplits = JSONUtils.getArray(jsonObject.optJSONArray(\"selected_splits\"));\n    }\n\n    public void validateForReplay() throws JSONException {\n        if (mInstallExisting) {\n            if (TextUtils.isEmpty(mPackageName)) {\n                throw new JSONException(\"Package name is missing.\");\n            }\n        } else {\n            if (mApkSource == null) {\n                throw new JSONException(\"APK source is missing.\");\n            }\n            if (mSelectedSplits == null || mSelectedSplits.isEmpty()) {\n                throw new JSONException(\"Selected APK splits are missing.\");\n            }\n        }\n        if (mInstallerOptions != null) {\n            setInstallerOptions(InstallerOptions.resolveEffectiveOptions(mInstallerOptions,\n                    mPackageName, mTestOnly));\n        }\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/ApkQueueItem.java#L213-L249","documentation":"ApkQueueItem.validateForReplay re-validates a deserialized install-queue item before generating its executable intent. If the item represents an 'install existing package' action (mInstallExisting) but no package name was stored, it throws JSONException because the replay intent cannot target any package.","triggerScenarios":"Replaying a queued install created from JSON where the \"install_existing\" flag is true but the \"package_name\" field is missing, null, or empty (TextUtils.isEmpty) — typically after hand-editing the queue file or an older schema version writing incomplete records.","commonSituations":"Restoring sessions from backup/restore of the app's install queue, importing queue JSON shared between devices with schema drift, or corrupt/partially written queue entries.","solutions":["Ensure the JSON record contains a non-empty \"package_name\" whenever \"install_existing\" is true.","Validate the queue JSON schema before deserializing (check optJSONObject/has on required keys).","Wrap validateForReplay/getExecutableIntent in try-catch for JSONException and skip/requeue invalid items.","Migrate old queue entries: if install_existing is set and package_name is blank, prompt the user to re-select the package or drop the item."],"exampleFix":"// before\nitem.validateForReplay();\nIntent intent = item.getExecutableIntent();\n// after\ntry {\n    item.validateForReplay();\n    Intent intent = item.getExecutableIntent();\n} catch (JSONException e) {\n    queue.remove(item); // drop malformed replay entry\n}","handlingStrategy":"validation","validationCode":"if (json.optBoolean(\"install_existing\") && TextUtils.isEmpty(json.optString(\"package_name\"))) {\n    throw new JSONException(\"install_existing requires package_name\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    item.validateForReplay();\n} catch (JSONException e) {\n    Log.w(TAG, \"Skipping invalid queue item: \" + e.getMessage());\n}","preventionTips":["Validate required JSON keys at deserialization time, before storing the queue item.","Version the queue JSON schema and migrate old entries on load.","Never write queue entries with install_existing=true and an empty package_name.","Fail soft during replay: skip invalid items instead of aborting the whole queue."],"tags":["android","json","validation","installer"],"backgroundTag":"missing-required-argument","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}