microsoft/semantic-kernel · error · AgentInvokeException

Conversation ID not found in start response.

Error message

Conversation ID not found in start response.

What it means

An AgentInvokeException raised when the conversation-start call succeeds (200/201) but the JSON response lacks a 'conversationId' field. Without a conversation id the activities URL cannot be constructed, so posting is impossible. This is a malformed-success-response condition.

Source

Thrown at python/samples/demos/copilot_studio_agent/src/direct_line_agent.py:192

        if not self.directline_token:
            await self._fetch_token_and_conversation()

        headers = {
            "Authorization": f"Bearer {self.directline_token}",
            "Content-Type": "application/json",
        }

        # Step 2: Start a conversation if one hasn't already been started.
        if not self.conversation_id:
            start_conv_url = f"{self.bot_endpoint}/conversations"
            async with self.session.post(start_conv_url, headers=headers) as resp:
                if resp.status not in (200, 201):
                    logger.error("Failed to start conversation. Status: %s", resp.status)
                    raise AgentInvokeException("Failed to start conversation.")
                conv_data = await resp.json()
                self.conversation_id = conv_data.get("conversationId")
                if not self.conversation_id:
                    raise AgentInvokeException("Conversation ID not found in start response.")

        # Step 3: Post the message payload.
        activities_url = f"{self.bot_endpoint}/conversations/{self.conversation_id}/activities"
        async with self.session.post(activities_url, json=payload, headers=headers) as resp:
            if resp.status != 200:
                logger.error("Failed to post activity. Status: %s", resp.status)
                raise AgentInvokeException("Failed to post activity.")
            _ = await resp.json()  # Response from posting activity is ignored.

        # Step 4: Poll for new activities using watermark until DynamicPlanFinished event is found.
        finished = False
        collected_data = None
        watermark = None
        while not finished:
            url = activities_url if watermark is None else f"{activities_url}?watermark={watermark}"
            async with self.session.get(url, headers=headers) as resp:
                if resp.status == 200:
                    data = await resp.json()

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Log the full conv_data to find the real conversation id field name.
  2. Confirm the endpoint is DirectLine v3 (which returns conversationId).
  3. If the key differs, adapt the parsing to read the correct field.

Example fix

// before
self.conversation_id = conv_data.get("conversationId")
if not self.conversation_id:
    raise AgentInvokeException("Conversation ID not found in start response.")

// after
self.conversation_id = conv_data.get("conversationId") or conv_data.get("id")
if not self.conversation_id:
    logger.error("Start-conversation body: %s", conv_data)
    raise AgentInvokeException("Conversation ID not found in start response.")
Defensive patterns

Strategy: validation

Type guard

def has_conversation_id(conv_data) -> bool:
    return isinstance(conv_data, dict) and bool(conv_data.get('conversationId') or conv_data.get('id'))

Try / catch

try:
    await agent.invoke(history)
except AgentInvokeException as e:
    if "Conversation ID not found" in str(e):
        logger.error("Start-conversation response schema unexpected.")
    raise

Prevention

When it happens

Trigger: POST /conversations returns 200/201 with a body like {} or {'id': ...} where the key isn't 'conversationId'.

Common situations: DirectLine API version returns a differently-named id field; a gateway altered the response; the endpoint isn't actually DirectLine.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/fee45da442c25d41. Report an issue: GitHub.