musistudio/claude-code-router · error

No Bot Gateway conversationRef is available for inbound bot

Error message

No Bot Gateway conversationRef is available for inbound bot response.

What it means

sendReplyToEvent() must route a reply back to the conversation an inbound bot event came from. It derives conversationRef from the event (conversationRefFromEvent) with the configured value as fallback; if both are empty it throws because there is nowhere to deliver the reply.

Source

Thrown at packages/core/src/agents/codex/cli-middleware-runtime.ts:5514

    };
    await this.sendDurable(outbound, { kind: "handoff", sourceKey: key });
    this.rememberForwarded(key);
    log("bot_gateway_forward_sent", {
      key,
      reason: decision.reason,
      textLen: text.length,
      threadId: params.threadId || "",
      turnId: params.turnId || ""
    });
  }

  async sendReplyToEvent(event, text, key) {
    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 });

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Set config.conversationRef as a fallback so replies always have a destination
  2. Inspect the inbound event payload and fix the gateway/forwarder that drops the conversation field
  3. Update to a version matching the gateway's current event schema if the field was renamed
  4. Skip non-conversational events early instead of attempting a reply

Example fix

// before
await gateway.sendReplyToEvent(event, text, key); // throws when event has no ref

// after
const ref = conversationRefFromEvent(event) || gateway.config.conversationRef;
if (ref) {
  await gateway.sendReplyToEvent(event, text, key);
} else {
  logger.warn("dropping reply: no conversationRef on event", event);
}
Defensive patterns

Strategy: validation

Validate before calling

const ref = conversationRefFromEvent(event) || gateway.config.conversationRef; if (!ref) { /* drop or alert instead of replying */ }

Type guard

function eventHasConversationRef(event) { return Boolean(conversationRefFromEvent(event)); }

Try / catch

try { await gateway.sendReplyToEvent(event, text, key); } catch (e) { if (/no conversationRef is available for inbound/i.test(String(e))) { log.warn("dropping reply", { event }); } else throw e; }

Prevention

When it happens

Trigger: Replying to a bot event that carries no conversation reference (malformed/webhook-replayed event, trimmed payload) while no config.conversationRef fallback exists.

Common situations: Webhook gateway forwarding events with the conversation field stripped; event objects constructed manually in tests without a conversationRef; schema change in the gateway payload renaming the conversation field; empty fallback config.

Related errors


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