yikart/AiToEarn · error

-32600

-32600

Error message

Invalid Request: Only one initialization request is allowed

What it means

During stateful session setup, the server received an `initialize` request but the POST body was a JSON-RPC batch containing more than one request. The library rejects this with -32600 and HTTP 400 because batching multiple messages including initialize could create ambiguous session state; only a single initialize request is allowed per batch.

Source

Thrown at project/aitoearn-backend/libs/nest-mcp/src/services/mcp-streamable-http.service.ts:202

  }

  /**
   * Handle requests in stateful mode
   */
  async handleStatefulRequest(
    req: HttpRequest,
    res: HttpResponse,
    body: unknown,
  ): Promise<void> {
    const sessionId = req.headers['mcp-session-id'] as string | undefined

    this.logger.debug(`[${sessionId || 'New'}] Handling stateful MCP request`)

    // Case 1: New initialization request
    if (!sessionId && this.isInitializeRequest(body)) {
      // Validate it's not a batch with multiple requests
      if (Array.isArray(body) && body.length > 1) {
        res.status(400).json({
          jsonrpc: '2.0',
          error: {
            code: -32600,
            message:
              'Invalid Request: Only one initialization request is allowed',
          },
          id: null,
        })
        return
      }

      // Build capabilities
      const capabilities = buildMcpCapabilities(
        this.mcpModuleId,
        this.toolRegistry,
        this.options,
      )

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Send the initialize request alone as a single JSON-RPC object, not inside an array.
  2. Initialize first, capture the Mcp-Session-Id response header, then batch or pipeline subsequent calls on that session if needed.
  3. If your client must batch, batch only post-initialization requests on an established session.

Example fix

// before
await fetch(url, { method: 'POST', body: JSON.stringify([initReq, listToolsReq]) })
// after
const res = await fetch(url, { method: 'POST', body: JSON.stringify(initReq) })
const sessionId = res.headers.get('mcp-session-id')
await fetch(url, { method: 'POST', headers: { 'mcp-session-id': sessionId }, body: JSON.stringify(listToolsReq) })
Defensive patterns

Strategy: validation

Validate before calling

const isBatch = Array.isArray(body)
if (isBatch && body.some((r: any) => r?.method === 'initialize') && body.length > 1) {
  throw new Error('initialize must be sent alone, not in a batch')
}

Type guard

function isSingleInitialize(body: unknown): body is { jsonrpc: '2.0'; method: 'initialize'; id: string | number } {
  return !Array.isArray(body) && typeof body === 'object' && body !== null && (body as any).method === 'initialize'
}

Try / catch

if (res.status === 400 && (await res.json())?.error?.code === -32600) {
  // resend initialize as a single, non-batched request
}

Prevention

When it happens

Trigger: POSTing a JSON array like `[ {initialize...}, {tools/list...} ]` (or any array with length > 1 where an element is an initialize request) to the MCP endpoint without a session ID.

Common situations: Clients implementing JSON-RPC batch support too aggressively, proxy/gateway code that coalesces requests into an array, or hand-rolled test scripts sending arrays of messages at once.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/fb7ab637e9034199. Report an issue: GitHub.