musistudio/claude-code-router · warning · Error

微信扫码登录会话不存在,请重新生成二维码。

Error message

微信扫码登录会话不存在,请重新生成二维码。

What it means

waitBotGatewayQrLogin() resolves the QR login session by sessionId in an in-memory map (qrSessions). Unknown IDs — never created, expired and evicted, or lost to a process restart — cannot be waited on, so the user is told (in Chinese) the WeChat QR session does not exist and to regenerate the QR code.

Source

Thrown at packages/core/src/agents/bot-gateway/qr-login-service.ts:128

      sessionId,
      stateDir,
      tenantId: bot.tenantId
    };
  } catch (error) {
    if (!registered) {
      closeQrClient(client);
    }
    throw error;
  }
}

export async function waitBotGatewayQrLogin(
  request: BotGatewayQrLoginWaitRequest
): Promise<BotGatewayQrLoginWaitResult> {
  const sessionId = request.sessionId.trim();
  const session = qrSessions.get(sessionId);
  if (!session) {
    throw new Error("微信扫码登录会话不存在,请重新生成二维码。");
  }

  const rawWait = await botGatewayClientRequest(session.client, "auth.qr.wait", {
    autoStart: true,
    config: session.integrationConfig,
    configOverride: {
      ...session.integrationConfig,
      transport: botGatewayWebSocketTransport(session.platform)
    },
    credentials: session.credentials,
    integrationId: session.integrationId,
    platform: session.platform,
    sessionId,
    tenantId: session.tenantId,
    timeoutMs: Math.max(1000, request.timeoutMs || 5000),
    verifyCode: request.verifyCode?.trim() || undefined
  }, session.timeoutMs);
  const auth = unwrapGatewayResult(rawWait);

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Catch the error and call startBotGatewayQrLogin() again to generate a fresh QR, then wait on the new sessionId
  2. Confirm you pass the exact sessionId from the start result, not another identifier
  3. Check whether the core process restarted between start and wait (sessions are in-memory only); use sticky routing if running multiple instances

Example fix

// before
const result = await waitBotGatewayQrLogin({ sessionId });

// after
try {
  const result = await waitBotGatewayQrLogin({ sessionId });
} catch (error) {
  if (error instanceof Error && error.message.includes("会话不存在")) {
    const started = await startBotGatewayQrLogin({ /* original request */ });
    sessionId = started.sessionId; // show new QR, then wait again
  } else {
    throw error;
  }
}
Defensive patterns

Strategy: fallback

Validate before calling

// Re-verify session freshness before a long wait; ultimately rely on fallback restart
// (no public accessor exists for qrSessions, so pre-validation is limited to using the id from start())

Try / catch

try {
  return await waitBotGatewayQrLogin({ sessionId });
} catch (error) {
  if (error instanceof Error && error.message.includes("会话不存在")) {
    const started = await startBotGatewayQrLogin(originalRequest);
    return await waitBotGatewayQrLogin({ sessionId: started.sessionId });
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling waitBotGatewayQrLogin() with a sessionId that was never returned by startBotGatewayQrLogin(), a stale sessionId from before a process restart/hot-reload, an expired/evicted session, or mixing up sessionId with botConfigId/integrationId.

Common situations: Frontend keeps polling after the server reloaded or redeployed; the wait outlived the QR session TTL; user returned to a stale page; multiple backend instances so the session lives in another process's memory.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/8d6c6d1aa420d1f2. Report an issue: GitHub.