expo/expo · error · Error

Expected ${paramLength} parameter(s), but got ${argsLength}

Error message

Expected ${paramLength} parameter(s), but got ${argsLength} argument(s) for the command "${command}".

What it means

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.

Source

Thrown at packages/@expo/cli/src/start/server/DevToolsPluginCliExtensionExecutor.ts:62

      throw new Error(
        `Plugin ${this.plugin.packageName} entryPoint "${this.plugin.cliExtensions.entryPoint}" ` +
          `escapes packageRoot (${this.plugin.packageRoot}); must be a relative path inside the package.`
      );
    }
    this.resolvedEntryPoint = resolved;
  }

  public validate({ command, args }: Omit<DevToolsPluginExecutorArguments, 'metroServerOrigin'>) {
    const commandElement = this.plugin.cliExtensions?.commands.find((c) => c.name === command);
    if (!commandElement) {
      throw new Error(`Command "${command}" not found in plugin ${this.plugin.packageName}`);
    }

    const paramLength = commandElement.parameters?.length ?? 0;
    const argsLength = Object.keys(args ?? {}).length;
    if (paramLength !== argsLength) {
      // Quick check to see if the lengths match
      throw new Error(
        `Expected ${paramLength} parameter(s), but got ${argsLength} argument(s) for the command "${command}".`
      );
    }

    const argsObj = (args ?? {}) as Record<string, unknown>;
    for (const param of commandElement.parameters ?? []) {
      if (!Object.prototype.hasOwnProperty.call(argsObj, param.name)) {
        throw new Error(
          `Parameter "${param.name}" not found in command "${command}" of plugin ${this.plugin.packageName}`
        );
      }
      // Enforce declared parameter type; don't rely on upstream Zod validation alone.
      const expected =
        param.type === 'confirm' ? 'boolean' : param.type === 'number' ? 'number' : 'string';
      const actual = typeof argsObj[param.name];
      if (actual !== expected) {
        throw new Error(
          `Parameter "${param.name}" of "${command}" expected ${expected} (declared "${param.type}"), got ${actual}.`

View on GitHub (pinned to b09195aac2)

Solutions

  1. Read the command's `parameters[]` from the manifest and pass exactly that set of keys.
  2. Align caller and plugin versions so the parameter signature matches.
  3. If you author the command, make the added parameter optional and update callers, or migrate them together.

Example fix

// before — command 'build' declares [{name:'platform'}]
await executor.execute({ command: 'build', args: { platform: 'ios', profile: 'release' } }); // 2 vs 1
// after
await executor.execute({ command: 'build', args: { platform: 'ios' } });
Defensive patterns

Strategy: validation

Validate before calling

const cmd = plugin.cliExtensions!.commands.find(c => c.name === command)!;
const expected = cmd.parameters?.length ?? 0;
if (Object.keys(args ?? {}).length !== expected) { /* reject */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of expo/expo@b09195aac2 (2026-08-12). Data as JSON: /api/errors/1b4832b2e439d28f. Report an issue: GitHub.