musistudio/claude-code-router · error · Error
Bot Gateway SDK client does not expose request().
Error message
Bot Gateway SDK client does not expose request().
What it means
createQrClient() instantiates the Bot Gateway SDK client and duck-types the result: it must expose callable request() and health() methods. If the SDK's client shape changed — different method names, an unawaited Promise, or a falsy object because spawning failed — this guard fires immediately instead of producing a confusing TypeError later.
Source
Thrown at packages/core/src/agents/bot-gateway/qr-login-service.ts:194
return { canceled: Boolean(session) };
}
async function createQrClient(bot: BotGatewayRuntimeConfig, stateDir: string): Promise<BotGatewayClientWithRequest> {
const sdk = await loadBotGatewaySdk();
const command = resolveBotGatewayCommand(sdk, bot);
const { electronRunAsNode, ...commandOptions } = command ?? {};
const client = sdk.createBotGatewayClient({
transport: "stdio",
env: {
...process.env,
...(electronRunAsNode ? { ELECTRON_RUN_AS_NODE: "1" } : {}),
BOT_GATEWAY_STATE_DIR: stateDir,
CODEXL_HOME: CONFIGDIR
},
...commandOptions
}) as BotGatewayClientWithRequest;
if (!client || typeof client.request !== "function" || typeof client.health !== "function") {
throw new Error("Bot Gateway SDK client does not expose request().");
}
attachBotGatewayStdioErrorHandler(client);
return client;
}
function resolveBotGatewayCommand(sdk: BotGatewaySdkModule, bot: BotGatewayRuntimeConfig): BotGatewayCommand | undefined {
if (bot.command) {
return {
args: bot.args,
command: resolveUserPath(bot.command),
cwd: bot.cwd ? resolveUserPath(bot.cwd) : process.cwd()
};
}
if (typeof sdk.bundledStdioPath !== "function") {
return undefined;
}
const bundledPath = sdk.bundledStdioPath();
const runnerPath = materializeBotGatewayStdioRunnerPath(bundledPath);View on GitHub (pinned to 99f24806c6)
Solutions
- Pin or upgrade @the-next-ai/bot-gateway-sdk to the exact version this code targets (check the repo lockfile)
- If the SDK now returns a Promise from createBotGatewayClient, await it before the check
- Inspect stdio error logs (attachBotGatewayStdioErrorHandler) to confirm the gateway process actually spawned with the right env (BOT_GATEWAY_STATE_DIR, CODEXL_HOME)
- If you own the SDK, restore request()/health() or update this adapter to the new client API
Example fix
// before
const client = createBotGatewayClient({...}) as BotGatewayClientWithRequest;
if (!client || typeof client.request !== "function" || typeof client.health !== "function") {
throw new Error("Bot Gateway SDK client does not expose request().");
}
// after — handle Promise-returning SDK versions
const maybeClient = createBotGatewayClient({...});
const client = (maybeClient as Awaited<typeof maybeClient> | BotGatewayClientWithRequest) instanceof Promise
? await maybeClient
: maybeClient as BotGatewayClientWithRequest;
if (!client || typeof client.request !== "function" || typeof client.health !== "function") {
throw new Error("Bot Gateway SDK client does not expose request().");
} Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the SDK surface before creating the client-dependent flow
const sdk = await import("@the-next-ai/bot-gateway-sdk");
if (typeof sdk.createBotGatewayClient !== "function") {
throw new Error("Incompatible bot-gateway SDK: createBotGatewayClient missing");
} Type guard
function isBotGatewayClientWithRequest(value: unknown): value is BotGatewayClientWithRequest {
return typeof value === "object" && value !== null &&
typeof (value as BotGatewayClientWithRequest).request === "function" &&
typeof (value as BotGatewayClientWithRequest).health === "function";
} Try / catch
try {
const client = await createQrClient(bot, options);
} catch (error) {
if (error instanceof Error && error.message.includes("does not expose request()")) {
// check installed SDK version vs expected; reinstall/rebuild
} else throw error;
} Prevention
- Lock the SDK version in the lockfile and verify it in CI
- Write a unit test asserting the client shape from the pinned SDK version
- Await any Promise-returning createBotGatewayClient before duck-typing
When it happens
Trigger: Loading an @the-next-ai/bot-gateway-sdk version whose createBotGatewayClient returns an object without request/health (renamed API), returns a Promise that must be awaited, or returns undefined/throws internally leaving client falsy after the cast to BotGatewayClientWithRequest.
Common situations: SDK major version bump in the lockfile without updating this service; resolution picking up an unexpected SDK copy (bundled vs node_modules); gateway binary spawn failing silently so the client is never fully constructed; refactor in the SDK to a class-based client.
Related errors
- Bot Gateway QR start response missing qrCodeUrl.
- Unable to load @the-next-ai/bot-gateway-sdk. ${errors.join("
- No Bot Gateway conversationRef is configured and no inbound
- No Bot Gateway conversationRef is available for inbound bot
- No Bot Gateway conversationRef is available for card respons
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/d9e5d0368d55522c.
Report an issue: GitHub.