fix(voice-bridge): match twiml-inbound route on pathname (per-profile voice 404)#263
Open
ssdavidai wants to merge 1 commit into
Open
fix(voice-bridge): match twiml-inbound route on pathname (per-profile voice 404)#263ssdavidai wants to merge 1 commit into
ssdavidai wants to merge 1 commit into
Conversation
…q.url The HTTP router matched the Twilio TwiML inbound route with `req.url === TWIML_INBOUND_PATH`, which compares the full request URL (including the query string) against the bare path "/twiml/inbound". Per-profile voice routing configures the Twilio number's VoiceUrl as `https://voice.<domain>/twiml/inbound?profile=<slug>`, and handleTwimlInbound reads the profile via searchParams.get("profile"). Because the router compared the full req.url ("/twiml/inbound?profile=...") against the bare path, any VoiceUrl carrying ?profile= 404'd before reaching the handler — so per-profile voice was completely broken and calls only worked with a bare /twiml/inbound, which always defaults to main. Fix: compare the URL pathname only, ignoring the query string, mirroring the existing /voice/<id> WSS route which already uses new URL(...).pathname. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
The voice-bridge HTTP router matched the Twilio TwiML inbound route by exact
req.url, which includes the query string:The per-profile voice feature (#120 Lane Vb) configures the Twilio number's
VoiceUrlashttps://voice.<domain>/twiml/inbound?profile=<slug>, andhandleTwimlInbound(intwiml.ts) reads the profile viareqUrl.searchParams.get("profile"). Because the router compared the fullreq.url(/twiml/inbound?profile=cratchit) against the bare path/twiml/inbound, any VoiceUrl carrying?profile=404'd before reaching the handler. Per-profile voice routing was therefore completely broken — calls only worked with a bare/twiml/inbound, which always defaults tomain.Live evidence (verified today on tenant joe.alfred.black)
POST /twiml/inbound→ 403 (served, signature-rejected — reaches the handler)POST /twiml/inbound?profile=cratchit→ 404 (rejected by the router before the handler)After the fix, both return 403 (served) and
?profile=cratchitcorrectly reaches the handler.The fix
Compare the URL pathname only, ignoring the query string:
This mirrors the existing
/voice/<id>WSS upgrade route, which already usesnew URL(...).pathnamematching.The other exact-match routes in the same handler (
/health,/metrics,/esphome/devices,/wyoming/status,/voice/recall-turn) are internal/health endpoints always called without query strings, so they are intentionally left unchanged.Verification
npx tsc --noEmitpasses clean inpackages/voice-bridge/.(Note: there may be an unrelated flaky CI check — please ignore.)
🤖 Generated with Claude Code