deepseek-ai/deepseek-harness · error

rpcId mismatch for ${endpoint}: sent ${rpcId}, got ${full.rp

Error message

rpcId mismatch for ${endpoint}: sent ${rpcId}, got ${full.rpcId}

What it means

Every unary call mints a random UUID rpcId, sends it inside the client-request envelope, and requires the server response envelope to echo it. A mismatch means the envelope answers a different request: typically a caching proxy or service worker replaying a stale response, an interleaving middlebox, or a server implementation that mints its own id instead of echoing the request's.

Source

Thrown at packages/client/connection/src/client/rpc.ts:49

        rpcId,
        method: endpoint,
        payload,
      }
      const response = await send(
        new URL(`${channel}/${endpoint}`, resolveBase()),
        {
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify(message),
          ...signal === undefined ? {} : { signal },
        },
      )
      if (!response.ok) {
        throw new Error(`transport failure for ${channel}/${endpoint}: HTTP ${response.status}`)
      }
      const full = serverResponseSchema.parse(await response.json())
      if (full.rpcId !== rpcId) {
        throw new Error(`rpcId mismatch for ${endpoint}: sent ${rpcId}, got ${full.rpcId}`)
      }
      return full.result
    },
  }
}

function resolveBase(): string {
  const location = (globalThis as { location?: { origin?: string } }).location
  return location?.origin !== undefined && location.origin !== 'null' ? location.origin : INTERNAL_BASE
}

function assertTarget(channel: string, endpoint: string): void {
  const segments = endpoint.split('/')
  if (!CHANNEL_PATTERN.test(channel)
    || segments.some(segment =>
      segment === '' || segment === '.' || segment === '..' || !ENDPOINT_SEGMENT_PATTERN.test(segment))) {
    throw new Error(`connection: invalid RPC target ${JSON.stringify(`${channel}/${endpoint}`)}`)
  }

View on GitHub (pinned to b150a551b8)

Solutions

  1. If you control the server, echo the request envelope's rpcId verbatim instead of minting one
  2. Disable HTTP and service-worker caching for the /api paths the RPC posts to
  3. Retry the call once with a fresh id when the operation is idempotent; the stale cached envelope is usually evicted by then

Example fix

// before — server builds its own id
const response = { type: 'server-response', rpcId: RpcId(randomUuid()), result }

// after — echo the request's id
const response = { type: 'server-response', rpcId: request.rpcId, result }
Defensive patterns

Strategy: retry

Try / catch

async function callRetrying(rpc, channel, endpoint, payload, attempts = 2) {
  for (let i = 0; ; i++) {
    try {
      return await rpc.call(channel, endpoint, payload)
    } catch (error) {
      if (i + 1 >= attempts || !String(error).includes('rpcId mismatch')) throw error
    }
  }
}

Prevention

When it happens

Trigger: rpc.call receives a schema-valid response whose rpcId differs from the sent one: HTTP or service-worker caches replaying an old POST response, a proxy mis-correlating concurrent requests, or a hand-written server that forgets to copy rpcId from request to response.

Common situations: A service worker or CDN configured to cache the RPC POST route; devtools offline-replay; a custom server generating fresh ids in the response envelope.

Related errors


AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24). Data as JSON: /api/errors/8879a23520766791. Report an issue: GitHub.