{"record":{"id":"d168c1e9137e9ad1","repo":"stablyai/orca","slug":"invalid-argument-d168c1","errorCode":"invalid_argument","errorMessage":"<op> must be grant, revoke, or reset","messagePattern":"<op> must be grant, revoke, or reset","errorType":"validation","errorClass":"RuntimeClientError","httpStatus":null,"severity":"error","filePath":"src/cli/emulator-permissions-args.ts","lineNumber":15,"sourceCode":"import { getOptionalStringFlag, getRequiredStringFlag } from './flags'\nimport { RuntimeClientError } from './runtime-client'\n\nexport type EmulatorPermissionRequest = {\n  op: 'grant' | 'revoke' | 'reset'\n  packageName?: string\n  permission?: string\n}\n\nexport function parseEmulatorPermissionRequest(\n  flags: Map<string, string | boolean>\n): EmulatorPermissionRequest {\n  const op = getRequiredStringFlag(flags, 'op')\n  if (op !== 'grant' && op !== 'revoke' && op !== 'reset') {\n    throw new RuntimeClientError('invalid_argument', '<op> must be grant, revoke, or reset')\n  }\n  const packageName = getOptionalStringFlag(flags, 'package')\n  const permission = getOptionalStringFlag(flags, 'permission')\n  if (op === 'reset') {\n    if (packageName || permission) {\n      throw new RuntimeClientError(\n        'invalid_argument',\n        'reset does not accept package or permission'\n      )\n    }\n    return { op }\n  }\n  if (!permission) {\n    throw new RuntimeClientError('invalid_argument', `<permission> is required for ${op}`)\n  }\n  return { op, packageName: packageName ?? getRequiredStringFlag(flags, 'package'), permission }\n}\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/cli/emulator-permissions-args.ts#L1-L33","documentation":"Thrown by parseEmulatorPermissionRequest when the required --op flag is set to anything other than 'grant', 'revoke', or 'reset'. The op is the discriminator for the whole request: grant/revoke need a permission (and optionally a package), reset takes neither. An unrecognized op cannot be mapped to an Android pm action, so it is rejected before any further parsing.","triggerScenarios":"Calling parseEmulatorPermissionRequest with a flags map whose 'op' entry is a string outside the set {grant, revoke, reset}, e.g. `new Map([['op','allow']])` or omitting a value so the parser coerces it incorrectly.","commonSituations":"Typo in an emulator-permission CLI command (`orca emulator permissions --op grannt`), a script passing a stale op name from an older API, or confusion with the host's own permission verb set.","solutions":["Pass --op as exactly 'grant', 'revoke', or 'reset'.","If you meant to wipe all permissions for a package, use --op reset (without --package/--permission).","Check the calling script against the EmulatorPermissionRequest type definition."],"exampleFix":"// before\nnew Map([['op','allow'],['permission','CAMERA']])\n\n// after\nnew Map([['op','grant'],['permission','CAMERA']])","handlingStrategy":"type-guard","validationCode":"const VALID_OPS = new Set(['grant', 'revoke', 'reset'])\nfunction pickOp(flags: Map<string, string | boolean>): 'grant' | 'revoke' | 'reset' {\n  const op = flags.get('op')\n  if (typeof op !== 'string' || !VALID_OPS.has(op)) {\n    throw new Error(`--op must be one of ${[...VALID_OPS].join('|')}`)\n  }\n  return op as 'grant' | 'revoke' | 'reset'\n}","typeGuard":"function isEmulatorPermissionOp(v: unknown): v is 'grant' | 'revoke' | 'reset' {\n  return v === 'grant' || v === 'revoke' || v === 'reset'\n}","tryCatchPattern":"try {\n  parseEmulatorPermissionRequest(flags)\n} catch (e) {\n  if (e instanceof RuntimeClientError && e.code === 'invalid_argument') {\n    // prompt user for a valid --op\n  }\n  throw e\n}","preventionTips":["Constrain --op to a literal union at the CLI surface.","In scripts, derive op from an enum rather than a free string."],"tags":["cli","emulator","permissions","invalid-argument"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}