Skip to content

fix(voice): prevent activity race during session shutdown - #2125

Open
smorimoto wants to merge 2 commits into
livekit:mainfrom
smorimoto:fix/agent-session-close-race
Open

fix(voice): prevent activity race during session shutdown#2125
smorimoto wants to merge 2 commits into
livekit:mainfrom
smorimoto:fix/agent-session-close-race

Conversation

@smorimoto

Copy link
Copy Markdown
Contributor

Closes #1871

Problem

AgentSession.closeImplInner dereferences this.activity across several await boundaries. An in-flight activity transition can clear the session field while shutdown is draining the activity, causing a TypeError at currentSpeech. The remaining cleanup and the Close event are then skipped.

Solution

Capture the active AgentActivity once and use that stable reference for interruption, draining, playout waiting, user-turn commit, input detachment, and final close. This also addresses the review feedback on #1872: the final close no longer reads the mutable session field.

A regression test pauses drain(), clears the session activity, and verifies that shutdown resolves, the captured activity closes, and the Close event fires. A patch changeset is included.

Verification

  • pnpm test agents/src/voice/agent_session.test.ts agents/src/voice/agent_session_close_race.test.ts agents/src/voice/agent_session_handoff.test.ts agents/src/voice/agent_activity_close_commit.test.ts (14 tests passed)
  • pnpm --filter @livekit/agents typecheck
  • pnpm build:agents
  • pnpm --filter @livekit/agents throws:check
  • pnpm -w format:check

The full pnpm test run completed 1,804 tests successfully. Its remaining failures were unrelated environment and integration cases: missing OpenAI and Cerebras API keys, Hugging Face download timeouts, and a Silero VAD fixture failure.

@changeset-bot

changeset-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6ab681e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 39 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-krisp Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-protoface Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@smorimoto
smorimoto marked this pull request as ready for review July 26, 2026 19:36
@smorimoto
smorimoto requested a review from a team as a code owner July 26, 2026 19:36

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae91133f51

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

this.output.transcription = null;

await this.activity?.close();
await activity?.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Close an activity resumed during shutdown

When an AgentTask completes while shutdown is awaiting cleanup, agent.ts:761-765 can call _updateActivity(..., { newActivity: 'resume' }); the closing guard at agent_session.ts:1284 blocks only start, so this transition can install and start the resumed activity. This line then closes only the earlier captured activity, and the following assignment clears the reference to the live resumed activity without closing it, allowing model/audio pipelines and background tasks to survive the session's Close event. Shutdown must either prevent resume transitions or also close any replacement activity.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6ab681eb9c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1293 to +1294
if (newActivity === 'resume') {
await this.nextActivity?.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid closing the paused activity from its own task

When an AgentTask completes after shutdown has set closing, this resume transition runs from the task that is still registered in the paused activity's speechTasks. Awaiting that activity's close() here makes AgentActivity.close() cancel and wait for the calling task itself; the task cannot finish until _updateActivity() returns, so shutdown stalls for the five-second REPLY_TASK_CANCEL_TIMEOUT (and may exceed the host's shutdown grace period). Defer this close until the caller has unwound, or exclude the current task from the close wait.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AgentSession.closeImplInner throws "Cannot read properties of undefined (reading 'currentSpeech')" when close races an activity transition

1 participant