{"record":{"id":"a5b16cb1a46cbb41","repo":"stablyai/orca","slug":"emulator-error-a5b16c","errorCode":"emulator_error","errorMessage":"pm ${op} requires a permission name","messagePattern":"pm (.+?) requires a permission name","errorType":"exception","errorClass":"EmulatorError","httpStatus":null,"severity":"error","filePath":"src/main/emulator/android/android-permissions.ts","lineNumber":25,"sourceCode":"\n// grant/revoke: `adb -s <serial> shell pm <op> <package> <permission>`\n// reset:        `adb -s <serial> shell pm reset-permissions <package>`\n// `reset` clears every runtime grant, so the permission argument is ignored.\nexport function permissionArgs(\n  serial: string,\n  op: AndroidPermissionOp,\n  packageName: string,\n  permission?: string\n): string[] {\n  const base = ['-s', serial, 'shell', 'pm']\n  // `pm reset-permissions` resets every app's runtime grants and rejects a\n  // package argument, so it is omitted here.\n  if (op === 'reset') {\n    return [...base, 'reset-permissions']\n  }\n  // grant/revoke target a single permission, so it must be present.\n  if (!permission || permission.trim() === '') {\n    throw new EmulatorError('emulator_error', `pm ${op} requires a permission name`)\n  }\n  return [...base, op, packageName, permission]\n}\n","sourceCodeStart":7,"sourceCodeEnd":29,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/emulator/android/android-permissions.ts#L7-L29","documentation":"Thrown by permissionArgs when op is 'grant' or 'revoke' but the permission argument is undefined, null, or empty/whitespace. The builder cannot construct a valid `adb shell pm grant <pkg> <perm>` line without a permission target. The 'reset' op is exempt because `pm reset-permissions` takes no permission argument.","triggerScenarios":"permissionArgs(serial, 'grant', pkg) or permissionArgs(serial, 'revoke', pkg) invoked with the fourth argument omitted or set to ''/whitespace. Typically a caller reading the permission name from a config or list that yielded an empty value.","commonSituations":"A permission grant loop iterating over a list that contains an empty entry; a config field left blank; reading the permission name from a JSON manifest that did not include the expected key; a guard missing before forwarding user input.","solutions":["Validate the permission name is a non-empty Android permission constant (e.g. android.permission.CAMERA) before calling permissionArgs.","Filter empty entries out of permission lists before iterating.","Skip grant/revoke entirely when no permission applies; use op 'reset' only when a full reset is intended."],"exampleFix":"// before: empty permission from config slips through\nfor (const p of manifest.permissions) {\n  await run(permissionArgs(serial, 'grant', pkg, p))\n}\n// after: guard non-empty canonical names\nfor (const p of manifest.permissions) {\n  if (!p?.startsWith('android.permission.')) continue\n  await run(permissionArgs(serial, 'grant', pkg, p))\n}","handlingStrategy":"validation","validationCode":"// Guard the permission argument before building args.\nfunction isValidPermission(p?: string): boolean {\n  return !!p && p.trim() !== '' && p.startsWith('android.permission.')\n}","typeGuard":"function isPermissionName(p?: string): p is string {\n  return !!p && p.trim() !== ''\n}","tryCatchPattern":null,"preventionTips":["Filter empty strings out of permission lists before iterating.","Validate permission names start with 'android.permission.' for standard perms.","Use op 'reset' only when no single permission is targeted."],"tags":["android","permissions","validation","adb"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}