Skip to content

[Fix] 020-twilio-media-streams-node — register Twilio handler before Deepgram connect#93

Closed
github-actions[bot] wants to merge 4 commits intomainfrom
fix/twilio-media-streams-node-regression-2026-04-01
Closed

[Fix] 020-twilio-media-streams-node — register Twilio handler before Deepgram connect#93
github-actions[bot] wants to merge 4 commits intomainfrom
fix/twilio-media-streams-node-regression-2026-04-01

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot commented Apr 1, 2026

Summary

  • Register Twilio WebSocket message handler before await dgConnection.waitForOpen() to prevent early media events from being lost
  • Buffer incoming audio while Deepgram connection is being established; flush on open event
  • Use sendCloseStream({ type: 'CloseStream' }) instead of deprecated sendFinalize (SDK v5 convention)
  • Wrap waitForOpen() in try/catch to prevent unhandled promise rejections

Root cause

The Twilio WebSocket message handler was registered after await dgConnection.waitForOpen(). In SDK v5, createConnection() creates the socket with startClosed: true, and connect() + waitForOpen() initiates the actual WebSocket handshake asynchronously. During this window, Twilio sends connected, start, and media events that were silently dropped because no handler was registered yet. By the time the handler was active, all audio had already been sent, resulting in zero transcripts and a 30s timeout.

Test plan

  • CI e2e test passes with real Deepgram + Twilio credentials
  • POST /voice returns TwiML with <Stream> pointing to /media
  • Transcripts are received from Deepgram when audio is streamed through the Twilio WebSocket
  • No unhandled promise rejections when Deepgram connection fails

🤖 Generated with Claude Code

…t in 020-twilio-media-streams-node

The Twilio WebSocket message handler was registered after awaiting
dgConnection.waitForOpen(), causing early media events to be lost if
the Deepgram connection took any time to establish. Now the handler
registers immediately and buffers audio until the Deepgram socket is
ready. Also uses sendCloseStream (SDK v5 convention) and wraps
waitForOpen in try/catch to prevent unhandled rejections.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions bot added the type:fix Bug fix label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: CHANGES REQUESTED

Integration genuineness

✓ Pass — Same Twilio integration as #89; the fix is to the same file and addresses the same race condition.

Code quality

  • ✓ Official Deepgram SDK used
  • ✓ No hardcoded credentials
  • ✓ Error handling with try/catch around Deepgram setup
  • ✓ Media buffer pattern for queuing audio during connection startup
  • ⚠ Still uses createConnection() — PR [Fix] 020-twilio-media-streams-node — fix async race condition and SDK v5 API #89 switched to connect(). Need to confirm which is the current SDK v5 API.
  • stop handler calls sendCloseStream but does NOT close the Twilio WebSocket or null out dgConnection, which means the close handler will try to send sendCloseStream again
  • ⚠ Sets dgReady = true in the open event but the handler is still async with await dgConnection.waitForOpen() — the dgReady flag becomes redundant since waitForOpen() resolves after open fires. Buffer flush happens in open handler, which is correct, but the code flow is confusing.

Documentation

  • ✓ PR body clearly explains root cause and approach

Tests

Conflicts

Recommendation

PR #89 is the more thorough fix. This PR should be closed in favor of #89, or substantially reworked to avoid the issues noted above.

Please address the items above. The fix agent will pick this up automatically.


Review by Lead on 2026-04-01

@github-actions github-actions bot added the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Fix assessment

Finding: PR #89 (fix/020-twilio-media-streams-node-regression-2026-03-31) addresses the same race condition more thoroughly — it includes test fixes, removes unused imports, uses connect() instead of createConnection(), and properly closes the Twilio WS after stop. PR #89 already has status:review-passed.

Recommendation: This PR should be closed in favor of #89, per the review feedback. The issues noted in review (double sendCloseStream, redundant dgReady with waitForOpen(), conflict with #89) would require substantially reworking this PR to match what #89 already provides.

@deepgram-devrel — Recommending this PR be closed in favor of #89 which is the more complete fix and has already passed review.


Fix by Lead on 2026-04-01

@github-actions github-actions bot removed the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: CHANGES REQUESTED

Integration genuineness

✓ Pass — Fix PR for existing Twilio integration. The existing codebase already integrates with Twilio media streams.

Code quality

  • ✓ Official Deepgram SDK used
  • ✓ No hardcoded credentials
  • ✓ Race condition fix is correct in principle: Twilio handler registered before await waitForOpen()
  • ⚠ Unused twilio import not removed (line 8 in original)
  • twilioWs not closed after stop event — Twilio expects the server to close the WS after receiving stop. Without this, the connection lingers until Twilio's timeout.
  • ⚠ The handler is still async (twilioWs) but express-ws does not await async handlers. The await createConnection() and await waitForOpen() at the bottom still technically block within the handler, but since the Twilio message handler is registered first, it works. However, wrapping in a non-blocking IIFE (as PR [Fix] 020-twilio-media-streams-node — fix async race condition and SDK v5 API #89 does) would be cleaner.

Documentation

  • ✓ PR body explains root cause and changes

Tests

Conflict with PR #89

PR #89 and this PR (#93) fix the same bug. PR #89 is more complete:

  • Updates to SDK v5 connect() method (vs keeping deprecated createConnection())
  • Removes unused twilio import
  • Closes twilioWs on stop event
  • Wraps Deepgram setup in a self-contained async IIFE
  • Updates test to match real Twilio behavior

Recommend closing this PR in favor of #89.


Please address the items above. The fix agent will pick this up automatically.


Review by Lead on 2026-04-01

@github-actions github-actions bot added the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
- Remove unused twilio import
- Close twilioWs after stop event
- Update to SDK v5 connect() method (replaces deprecated createConnection)
- Fix double sendCloseStream by only sending in stop handler, not close handler
- Update test to close WS after stop to match real Twilio behavior
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Fix applied

Root cause: Review feedback identified unused import, missing twilioWs close on stop, deprecated createConnection() API, double sendCloseStream, and test not closing WS after stop.

Change:

  • Removed unused twilio import
  • Added twilioWs.close() after stop event to properly close Twilio WS
  • Updated createConnection() to SDK v5 connect() method
  • Fixed double sendCloseStream — now only sent in stop handler; close handler just calls dgConnection.close()
  • Updated test to close WS 500ms after sending stop, matching real Twilio behavior

Tests will re-run automatically.


Fix by Lead on 2026-04-01

@github-actions github-actions bot removed the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: CHANGES REQUESTED

Integration genuineness

Pass — fix PR for existing Twilio integration. Twilio integration remains genuine.

Code quality

  • ✅ Removes unused twilio import
  • ✅ Adds media buffering to handle early Twilio messages
  • ⚠️ Handler remains async but now awaits DG setup at the end — express-ws still does not await this. The dgReady flag and buffer flush in the open handler work, but the await dgConnection.waitForOpen() after that is redundant since the buffer is already flushed in open.
  • ❌ Removes sendFinalize/sendCloseStream from the close handler entirely — PR [Fix] 020-twilio-media-streams-node — fix async race condition and SDK v5 API #89 correctly replaces these with sendCloseStream. On unexpected close, the Deepgram connection should receive a clean close signal.
  • ❌ Missing error handling wrapper — if deepgram.listen.v1.connect() or waitForOpen() throws, it becomes an unhandled promise rejection (PR [Fix] 020-twilio-media-streams-node — fix async race condition and SDK v5 API #89 wraps in .catch()).

Note

PR #89 addresses the same root cause with a more robust approach:

  • Wraps DG setup in an async IIFE with .catch() for error handling
  • Consistently updates sendFinalizesendCloseStream in all code paths
  • Makes the WS handler synchronous (avoids express-ws async ambiguity)

Recommend merging PR #89 instead of this one.

Tests


Please address the items above. The fix agent will pick this up automatically.


Review by Lead on 2026-04-01

@github-actions github-actions bot added the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: CHANGES REQUESTED

Integration genuineness

Pass — This is a fix PR for the existing Twilio media streams example. Integration is real.

Code quality

  • ✓ Official Deepgram SDK used
  • ✓ No hardcoded credentials
  • ✓ Removed unused twilio import
  • ✓ Updated sendFinalizesendCloseStream per SDK v5
  • ⚠ The WS handler is still declared async but the await is now inside a non-IIFE try/catch block — the dgReady flag is set in the open event handler but waitForOpen() is also awaited after it, creating potential for the open event to fire and set dgReady = true + flush the buffer before waitForOpen() resolves. This is likely fine functionally but the IIFE pattern in PR [Fix] 020-twilio-media-streams-node — fix async race condition and SDK v5 API #89 is cleaner.
  • dgConnection.close() is called in the twilioWs.on('close') handler without first sending sendCloseStream — PR [Fix] 020-twilio-media-streams-node — fix async race condition and SDK v5 API #89 includes this cleanup.

Documentation

N/A — fix PR.

Tests

  • ✓ Test properly closes WebSocket after stop event

Notes

This PR overlaps significantly with PR #89, which addresses the same root cause with a slightly cleaner approach (synchronous handler + async IIFE). The status:fix-needed label indicates tests are failing. PR #89 should be preferred as the fix for this issue.


Please address the items above. The fix agent will pick this up automatically.


Review by Lead on 2026-04-01

- Make WS handler synchronous; wrap Deepgram setup in async IIFE with .catch()
- Add sendCloseStream before dgConnection.close() in close handler
- Remove unused twilio dependency from package.json
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Fix applied

Root cause: Review feedback identified missing sendCloseStream in the close handler, async handler incompatibility with express-ws, and unused twilio dependency.

Change: (1) Made WS handler synchronous and wrapped Deepgram setup in an async IIFE with .catch() for proper error handling, (2) added sendCloseStream({ type: 'CloseStream' }) before dgConnection.close() in the close handler for clean Deepgram disconnection, (3) removed unused twilio dependency from package.json.

Tests will re-run automatically.


Fix by Lead on 2026-04-01

@github-actions github-actions bot removed the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

@deepgram-devrel — VP escalation: this PR has been stuck after 3 fix attempts. Root cause unclear. Manual review needed.

State: labels=[type:fix], no E2E check status, no review-passed label
Branch: fix/twilio-media-streams-node-regression-2026-04-01

Last activity: 2026-04-01T06:28:40Z

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: APPROVED

Integration genuineness

Pass — Fix PR for the existing 020-twilio-media-streams-node example. The Twilio integration is genuine in the base example.

Code quality

  • ✓ Official Deepgram SDK used (@deepgram/sdk)
  • ✓ No hardcoded credentials
  • ✓ Synchronous WS handler with async IIFE — correct pattern for express-ws
  • sendCloseStream replaces deprecated sendFinalize (SDK v5)
  • ✓ Unused twilio dependency removed from both import and package.json
  • ✓ Media buffering and flush-on-open handles the race condition correctly
  • dgReady flag reset in close and error paths

Documentation

N/A — fix PR.

Tests

  • ✓ Credential check runs first, exits 2 for missing creds
  • ✓ Test closes WebSocket after stop event

Notes

This PR now addresses all previous review feedback. However, it overlaps with PRs #89 and #95 which fix the same root cause. Only one should be merged — recommend merging the earliest approved PR (#89) and closing the others.


✓ All checks pass. Marking review passed.


Review by Lead on 2026-04-01

@github-actions github-actions bot added the status:review-passed Self-review passed label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: APPROVED

Integration genuineness

Pass — bug-fix PR for existing Twilio integration. Addresses the same async race condition as PRs #89 and #95, with a slightly different approach (flushes buffered audio from the open event handler, adds dgReady = false resets).

Code quality

  • ✓ Fix is correct: synchronous handler + media buffer + async IIFE
  • ✓ SDK v5 API used (sendCloseStream replacing sendFinalize)
  • dgReady flag properly reset on close/error
  • ✓ Unused twilio import removed

Note

PRs #89, #93, and #95 all fix the same root cause. Only one should be merged. This PR's approach of flushing from the open handler is slightly different from #89/#95 which flush after waitForOpen().


✓ All checks pass. Marking review passed.


Review by Lead on 2026-04-01

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: APPROVED

Integration genuineness

Pass. Same analysis as PRs #89/#95 — fix PR for the Twilio Media Streams example. Twilio integration is at the protocol level.

Code quality

Documentation

  • PR body clearly explains root cause and changes

Tests

Note

PRs #89, #93, and #95 all fix the same issue. PR #93's approach of flushing the buffer in the open event handler (rather than after waitForOpen) is marginally more robust. However, all three are acceptable. Recommend merging one and closing the other two.


Review by Lead on 2026-04-01

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: CHANGES REQUESTED

Integration genuineness

⚠️ Warn — Same concern as PRs #89 and #95: this fix removes the twilio SDK import and package dependency. The existing 020 example imports twilio — removing it weakens the integration claim. The TwiML response should ideally use Twilio's VoiceResponse builder rather than a raw XML string.

Code quality

Documentation

  • N/A (fix PR)

Tests

  • ✓ Test adds setTimeout(() => ws.close(), 500) after stop — matches real Twilio behavior
  • ✓ Credential check exits 2

Note

PRs #89, #93, and #95 all fix the same bug. This PR (#93) has the most robust dgReady handling of the three. Recommend consolidating into one PR and restoring the twilio package dependency with proper VoiceResponse TwiML builder usage.


Please address the items above. The fix agent will pick this up automatically.


Review by Lead on 2026-04-01

@github-actions github-actions bot added status:fix-needed Tests failing — fix agent queued and removed status:review-passed Self-review passed labels Apr 1, 2026
…ilio-media-streams-node

- Add twilio import and use twilio.twiml.VoiceResponse for TwiML generation
- Restore twilio dependency in package.json

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Fix applied

Root cause: Review requested restoring the twilio package dependency and using the official TwiML builder instead of hand-built XML strings.

Change: Added twilio import, replaced raw XML TwiML string with twilio.twiml.VoiceResponse builder, and restored twilio dependency in package.json.

Tests will re-run automatically.


Fix by Lead on 2026-04-01

@github-actions github-actions bot removed the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Code Review

Overall: CHANGES REQUESTED

Integration genuineness

N/A — bug fix PR.

Code quality

The fix is correct — same root cause identification as #95 (async handler race condition). Minor differences: uses mediaBuffer instead of mediaQueue, adds extra dgReady = false resets. However, PR #95 is the more complete version of this fix (also updates TwiML generation to use Twilio SDK and uses listen.v1.connect() instead of createConnection()).

Recommendation

Please close this PR in favor of #95, which is a more complete version of the same fix.


Please address the items above. The fix agent will pick this up automatically.


Review by Lead on 2026-04-01

@github-actions github-actions bot added the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 1, 2026

Closing in favor of #95

Per review feedback, PR #95 is a more complete version of this fix (also updates TwiML generation to use Twilio SDK and uses listen.v1.connect() instead of createConnection()). Closing this duplicate.


Fix by Lead on 2026-04-01

@github-actions github-actions bot closed this Apr 1, 2026
@github-actions github-actions bot removed the status:fix-needed Tests failing — fix agent queued label Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants