rohitg00/ai-engineering-from-scratch · error · RpcProblem

-32602

-32602

Error message

params must be an object

What it means

Every request to this server must carry params as a plain object (not an array, string, number, or null); arrays and non-objects are rejected with -32602 Invalid params. This is stricter than bare JSON-RPC because handlers read named fields off params.

Source

Thrown at phases/13-tools-and-protocols/07-building-an-mcp-server/code/main.ts:168

  return {
    resultType: "complete",
    ...payload,
    ...(cache ?? {}),
    _meta: { [SERVER_INFO_KEY]: { ...SERVER_INFO } },
  };
}

function validateRequest(message: JsonRpcRequest): void {
  if (message.jsonrpc !== "2.0" || typeof message.method !== "string") {
    throw new RpcProblem(-32600, "Invalid Request");
  }
  const requestId: unknown = message.id;
  if (requestId !== undefined && !isValidRequestId(requestId)) {
    throw new RpcProblem(-32600, "id must be a string or integer");
  }
  const params = message.params;
  if (!params || typeof params !== "object" || Array.isArray(params)) {
    throw new RpcProblem(-32602, "params must be an object");
  }
  const meta = params._meta;
  if (!meta || typeof meta !== "object" || Array.isArray(meta)) {
    throw new RpcProblem(-32602, "params._meta is required");
  }
  const requested = meta[VERSION_KEY];
  if (typeof requested !== "string") {
    throw new RpcProblem(-32602, `${VERSION_KEY} is required`);
  }
  if (!SUPPORTED_VERSIONS.includes(requested)) {
    throw new RpcProblem(-32022, "Unsupported protocol version", {
      requested,
      supported: [...SUPPORTED_VERSIONS],
    });
  }
  const capabilities = meta[CAPABILITIES_KEY];
  if (!capabilities || typeof capabilities !== "object" || Array.isArray(capabilities)) {
    throw new RpcProblem(-32602, `${CAPABILITIES_KEY} is required`);

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Wrap arguments in an object: params:{...} not params:[...]
  2. Double-check the JSON serializer is not flattening objects to strings

Example fix

// before
{ jsonrpc: '2.0', id: 1, method: 'tools/list', params: [] }
// after
{ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }
Defensive patterns

Strategy: validation

Validate before calling

if (!params || typeof params !== 'object' || Array.isArray(params)) params = {};

Type guard

function isJsonObject(v: unknown): v is Record<string, unknown> { 
  return typeof v === 'object' && v !== null && !Array.isArray(v); 
}

Prevention

When it happens

Trigger: Calling dispatch with params:[], params:'x', params:5, or params omitted and no default applied (dispatch does pass {} when params is undefined, but validateRequest rejects anything present but non-object).

Common situations: Clients modeling tool arguments as arrays, or serializing params to a JSON string before sending.

Related errors


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/e44e6ccf99f4ae4a. Report an issue: GitHub.