musistudio/claude-code-router · error
No Bot Gateway conversationRef is available for card respons
Error message
No Bot Gateway conversationRef is available for card response.
What it means
sendCardToEvent() sends a rich card as a bot reply and, like sendReplyToEvent, resolves the destination from the event's conversation reference with the configured conversationRef as fallback. When neither is present it throws before building the outbound message. Cards additionally get zh-CN localization before sending.
Source
Thrown at packages/core/src/agents/codex/cli-middleware-runtime.ts:5527
if (!text || !String(text).trim()) return;
await this.ensureStarted();
text = localizeBotReply(String(text), botLanguageForEvent(this.config.language, event));
const conversationRef = conversationRefFromEvent(event) || this.config.conversationRef;
if (!conversationRef) {
throw new Error("No Bot Gateway conversationRef is available for inbound bot response.");
}
const chunks = splitBotMessage(String(text), this.config.messageChunkChars);
for (let index = 0; index < chunks.length; index += 1) {
const chunk = chunks[index];
const outbound = this.outboundForEvent(event, conversationRef, botTextIntent(chunk), key + ":part:" + (index + 1));
await this.sendDurable(outbound, { kind: "reply", sourceKey: key });
}
}
async sendCardToEvent(event, card, fallbackText, key) {
await this.ensureStarted();
const conversationRef = conversationRefFromEvent(event) || this.config.conversationRef;
if (!conversationRef) throw new Error("No Bot Gateway conversationRef is available for card response.");
const language = botLanguageForEvent(this.config.language, event);
const localizedFallback = localizeBotReply(fallbackText, language);
const localizedCard = language === "zh-CN" ? localizeBotCard(card) : card;
const outbound = this.outboundForEvent(event, conversationRef, { type: "card", card: localizedCard, fallbackText: localizedFallback }, key);
await this.sendDurable(outbound, { kind: "card", sourceKey: key });
}
async sendMediaToEvent(event, media, caption, key) {
if (!this.config.mediaEnabled) return;
await this.ensureStarted();
const conversationRef = conversationRefFromEvent(event) || this.config.conversationRef;
if (!conversationRef) throw new Error("No Bot Gateway conversationRef is available for media response.");
const fallbackText = caption || media.filename || media.url || "Attachment";
const outbound = this.outboundForEvent(event, conversationRef, { type: "media", media, caption, fallbackText }, key);
await this.sendDurable(outbound, { kind: "media", sourceKey: key });
}
async sendStreamToEvent(event, streamId, text, final, key) {View on GitHub (pinned to 99f24806c6)
Solutions
- Configure conversationRef in the bot gateway settings as fallback
- Fix the event source so conversation fields survive forwarding to the middleware
- Send localized fallbackText via sendReplyToEvent as a degraded path when no ref can be resolved for cards
- Validate inbound events contain a conversation reference before enabling card responses
Example fix
// before
await gateway.sendCardToEvent(event, card, fallbackText, key); // throws: no ref
// after
const ref = conversationRefFromEvent(event) || gateway.config.conversationRef;
if (ref) {
await gateway.sendCardToEvent(event, card, fallbackText, key);
} else {
await gateway.sendReplyToEvent(event, fallbackText, key); // degrade to plain text reply if ref exists later
} Defensive patterns
Strategy: validation
Validate before calling
const ref = conversationRefFromEvent(event) || gateway.config.conversationRef; if (!ref) { /* skip card, send plain fallback, or alert */ } Type guard
function canSendCardToEvent(event, config) { return Boolean(conversationRefFromEvent(event) || config.conversationRef); } Try / catch
try { await gateway.sendCardToEvent(event, card, fallback, key); } catch (e) { if (/no conversationRef is available for card/i.test(String(e))) { await gateway.sendReplyToEvent(event, fallback, key).catch(() => {}); } else throw e; } Prevention
- Configure conversationRef fallback for card responses
- Ensure event payloads pass through the gateway unmodified
- Degrade to fallbackText replies when card routing is unavailable
When it happens
Trigger: Sending a card response to an inbound event lacking any conversation reference while no config.conversationRef fallback is configured — e.g. truncated webhook payloads or manually constructed event objects.
Common situations: Same class as text replies: gateway/forwarder stripping conversation fields, schema drift after a Bot Gateway upgrade, test fixtures missing conversationRef, missing gateway config section.
Related errors
- No Bot Gateway conversationRef is available for inbound bot
- No Bot Gateway conversationRef is configured and no inbound
- No Bot Gateway conversationRef is available for media respon
- Bot Gateway QR start response missing qrCodeUrl.
- Bot Gateway SDK client does not expose request().
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/a213db202c9120e9.
Report an issue: GitHub.