{"record":{"id":"d66ac61eee61f911","repo":"musistudio/claude-code-router","slug":"no-bot-gateway-conversationref-is-available-for-me","errorCode":null,"errorMessage":"No Bot Gateway conversationRef is available for media response.","messagePattern":"No Bot Gateway conversationRef is available for media response\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/agents/codex/cli-middleware-runtime.ts","lineNumber":5539,"sourceCode":"    }\n  }\n\n  async sendCardToEvent(event, card, fallbackText, key) {\n    await this.ensureStarted();\n    const conversationRef = conversationRefFromEvent(event) || this.config.conversationRef;\n    if (!conversationRef) throw new Error(\"No Bot Gateway conversationRef is available for card response.\");\n    const language = botLanguageForEvent(this.config.language, event);\n    const localizedFallback = localizeBotReply(fallbackText, language);\n    const localizedCard = language === \"zh-CN\" ? localizeBotCard(card) : card;\n    const outbound = this.outboundForEvent(event, conversationRef, { type: \"card\", card: localizedCard, fallbackText: localizedFallback }, key);\n    await this.sendDurable(outbound, { kind: \"card\", sourceKey: key });\n  }\n\n  async sendMediaToEvent(event, media, caption, key) {\n    if (!this.config.mediaEnabled) return;\n    await this.ensureStarted();\n    const conversationRef = conversationRefFromEvent(event) || this.config.conversationRef;\n    if (!conversationRef) throw new Error(\"No Bot Gateway conversationRef is available for media response.\");\n    const fallbackText = caption || media.filename || media.url || \"Attachment\";\n    const outbound = this.outboundForEvent(event, conversationRef, { type: \"media\", media, caption, fallbackText }, key);\n    await this.sendDurable(outbound, { kind: \"media\", sourceKey: key });\n  }\n\n  async sendStreamToEvent(event, streamId, text, final, key) {\n    if (!this.config.streamReplies || !text) return;\n    await this.ensureStarted();\n    const conversationRef = conversationRefFromEvent(event) || this.config.conversationRef;\n    if (!conversationRef) return;\n    const outbound = this.outboundForEvent(event, conversationRef, {\n      type: \"stream_text\",\n      streamId,\n      text,\n      final: Boolean(final),\n      fallbackText: text\n    }, key + \":\" + (final ? \"final\" : stableBotKey(text.slice(-160))));\n    await this.sendDurable(outbound, { kind: \"stream\", sourceKey: key });","sourceCodeStart":5521,"sourceCodeEnd":5557,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/agents/codex/cli-middleware-runtime.ts#L5521-L5557","documentation":"Thrown by sendMediaToEvent when the middleware cannot resolve a Bot Gateway conversationRef for the event. The code first tries conversationRefFromEvent(event) and then falls back to this.config.conversationRef; if both are undefined there is no routing address to deliver the media payload to, so it refuses to send.","triggerScenarios":"Calling sendMediaToEvent(event, media, ...) with mediaEnabled=true on an event that carries no conversation reference (e.g. a synthetic or webhook event without a conversationRef field) while the runtime was started without config.conversationRef, or before conversationRef was populated.","commonSituations":"Testing with mock/seeded events that omit conversationRef; misconfigured middleware where the default conversationRef option was not passed at construction; processing events from a different channel type that doesn't embed a conversationRef.","solutions":["Pass a conversationRef in the middleware config: new CodexCliMiddlewareRuntime({ conversationRef, ... }) so a fallback always exists","Ensure the event object actually contains the Bot Gateway conversationRef payload before calling sendMediaToEvent","If the event is optional, guard with conversationRefFromEvent(event) ?? config.conversationRef before calling and skip sending when absent"],"exampleFix":"// before\nawait runtime.sendMediaToEvent(event, media, caption);\n// after\nif (conversationRefFromEvent(event) || runtime.config.conversationRef) {\n  await runtime.sendMediaToEvent(event, media, caption);\n} else {\n  // log and skip media delivery\n}","handlingStrategy":"validation","validationCode":"const ref = conversationRefFromEvent(event) ?? runtime.config.conversationRef;\nif (!ref) {\n  // skip media delivery, log context\n  return;\n}\nawait runtime.sendMediaToEvent(event, media, caption, key);","typeGuard":"function hasConversationRef(event: unknown): boolean {\n  return conversationRefFromEvent(event as never) != null;\n}","tryCatchPattern":"try { await runtime.sendMediaToEvent(event, media, caption); } catch (e) { if (e instanceof Error && e.message.includes('conversationRef')) { /* degrade gracefully */ } else throw e; }","preventionTips":["Always configure a default conversationRef on the middleware","Validate events carry a conversationRef before processing media","Log event shape when the ref is missing to spot upstream payload changes"],"tags":["bot-gateway","conversation-ref","media","configuration"],"backgroundTag":"missing-conversation-reference","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}