{"record":{"id":"1b4832b2e439d28f","repo":"expo/expo","slug":"expected-paramlength-parameter-s-but-got-ar","errorCode":null,"errorMessage":"Expected ${paramLength} parameter(s), but got ${argsLength} argument(s) for the command \"${command}\".","messagePattern":"Expected (.+?) parameter\\(s\\), but got (.+?) argument\\(s\\) for the command \"(.+?)\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@expo/cli/src/start/server/DevToolsPluginCliExtensionExecutor.ts","lineNumber":62,"sourceCode":"      throw new Error(\n        `Plugin ${this.plugin.packageName} entryPoint \"${this.plugin.cliExtensions.entryPoint}\" ` +\n          `escapes packageRoot (${this.plugin.packageRoot}); must be a relative path inside the package.`\n      );\n    }\n    this.resolvedEntryPoint = resolved;\n  }\n\n  public validate({ command, args }: Omit<DevToolsPluginExecutorArguments, 'metroServerOrigin'>) {\n    const commandElement = this.plugin.cliExtensions?.commands.find((c) => c.name === command);\n    if (!commandElement) {\n      throw new Error(`Command \"${command}\" not found in plugin ${this.plugin.packageName}`);\n    }\n\n    const paramLength = commandElement.parameters?.length ?? 0;\n    const argsLength = Object.keys(args ?? {}).length;\n    if (paramLength !== argsLength) {\n      // Quick check to see if the lengths match\n      throw new Error(\n        `Expected ${paramLength} parameter(s), but got ${argsLength} argument(s) for the command \"${command}\".`\n      );\n    }\n\n    const argsObj = (args ?? {}) as Record<string, unknown>;\n    for (const param of commandElement.parameters ?? []) {\n      if (!Object.prototype.hasOwnProperty.call(argsObj, param.name)) {\n        throw new Error(\n          `Parameter \"${param.name}\" not found in command \"${command}\" of plugin ${this.plugin.packageName}`\n        );\n      }\n      // Enforce declared parameter type; don't rely on upstream Zod validation alone.\n      const expected =\n        param.type === 'confirm' ? 'boolean' : param.type === 'number' ? 'number' : 'string';\n      const actual = typeof argsObj[param.name];\n      if (actual !== expected) {\n        throw new Error(\n          `Parameter \"${param.name}\" of \"${command}\" expected ${expected} (declared \"${param.type}\"), got ${actual}.`","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/expo/expo/blob/b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee/packages/@expo/cli/src/start/server/DevToolsPluginCliExtensionExecutor.ts#L44-L80","documentation":"Thrown by DevToolsPluginCliExtensionExecutor.validate when the number of keys in the supplied `args` object does not equal the number of declared parameters on the command. This is the fast arity check that runs before the per-parameter presence/type loop. The message reports both counts and the command name so the mismatch is obvious.","triggerScenarios":"Invoking `executor.execute({ command, args })` where `Object.keys(args).length` differs from `commandElement.parameters.length`. Examples: passing an extra arg the command does not declare, omitting a required parameter, or passing args against a zero-parameter command.","commonSituations":"Caller and plugin drifted on the command signature (new parameter added/removed); extra debug arg accidentally included; default empty object passed when the command actually requires parameters; test fixture with a stale arg list.","solutions":["Read the command's `parameters[]` from the manifest and pass exactly that set of keys.","Align caller and plugin versions so the parameter signature matches.","If you author the command, make the added parameter optional and update callers, or migrate them together."],"exampleFix":"// before — command 'build' declares [{name:'platform'}]\nawait executor.execute({ command: 'build', args: { platform: 'ios', profile: 'release' } }); // 2 vs 1\n// after\nawait executor.execute({ command: 'build', args: { platform: 'ios' } });","handlingStrategy":"validation","validationCode":"const cmd = plugin.cliExtensions!.commands.find(c => c.name === command)!;\nconst expected = cmd.parameters?.length ?? 0;\nif (Object.keys(args ?? {}).length !== expected) { /* reject */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build args from the command's declared parameters, not from a free-form object.","Generate TypeScript types from the manifest to catch arity at compile time."],"tags":["devtools-plugin","cli-extension","validation","arity","api-misuse"],"backgroundTag":null,"analyzedSha":"b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee","analyzedAt":"2026-08-12T15:59:58.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}