Skip to content

fix: cache participant attrs for BYE attributes_to_headers (#404) - #775

Open
lixuanqun wants to merge 1 commit into
livekit:mainfrom
lixuanqun:cursor/fix-bye-attrs-headers-33f3
Open

fix: cache participant attrs for BYE attributes_to_headers (#404)#775
lixuanqun wants to merge 1 commit into
livekit:mainfrom
lixuanqun:cursor/fix-bye-attrs-headers-33f3

Conversation

@lixuanqun

Copy link
Copy Markdown

When an agent hangs up by deleting the room, LocalParticipant is gone before SIP sends BYE, so attributes_to_headers mapping was skipped and custom X-* headers were missing.

Cache the last-seen participant attributes on join/update and reuse them when building BYE/REFER headers if the room is already nil. Applies to inbound and outbound calls.

Fixes #404

When an agent hangs up by deleting the room, LocalParticipant is gone
before SIP sends BYE, so attributes_to_headers mapping was skipped and
custom X-* headers were missing.

Cache the last-seen participant attributes on join/update and reuse them
when building BYE/REFER headers if the room is already nil. Applies to
inbound and outbound calls.

Fixes livekit#404

Co-authored-by: li xuanqun <793005378@qq.com>
@lixuanqun
lixuanqun requested a review from a team as a code owner August 4, 2026 03:32

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment thread pkg/sip/inbound.go
Comment on lines +1817 to +1820
attrs := r.LocalParticipant.Attributes() // clones
c.attrsMu.Lock()
c.cachedAttrs = attrs
c.attrsMu.Unlock()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Saved caller attributes can be wiped out by an empty refresh, so custom hangup headers are lost again

The stored copy of the caller's attributes is unconditionally replaced with whatever the live room reports (c.cachedAttrs = attrs at pkg/sip/inbound.go:1817-1820), even when that live report is empty, so the values kept for the hangup message can be erased and the custom headers go missing again.
Impact: In the exact teardown situation this change is meant to fix, the outgoing hangup can still be sent without the configured custom headers.

How an empty live read overwrites the seeded cache

snapshotParticipantAttrs (inbound pkg/sip/inbound.go:1809-1821, outbound pkg/sip/outbound.go:183-195) writes c.cachedAttrs = attrs with no length check, unlike storeParticipantAttrs which deliberately ignores empty input (pkg/sip/inbound.go:1824). Right after seeding the cache from the join config (pkg/sip/inbound.go:1556-1557 and pkg/sip/outbound.go:508-509) a snapshot is taken immediately; if LocalParticipant.Attributes() has not yet been populated it returns an empty map and the seed is discarded. The same holds for participantAttributes() (pkg/sip/inbound.go:1832-1836), which snapshots first: if the room object still exists during teardown but the local participant's attribute map has already been cleared, the good cache is replaced with an empty one and fillHeaders then returns the headers untouched (pkg/sip/inbound.go:1799-1801).

Guarding the write with if len(attrs) == 0 { return } makes the snapshot strictly additive/refreshing and keeps the fallback usable.

Suggested change
attrs := r.LocalParticipant.Attributes() // clones
c.attrsMu.Lock()
c.cachedAttrs = attrs
c.attrsMu.Unlock()
attrs := r.LocalParticipant.Attributes() // clones
if len(attrs) == 0 {
return // do not drop a previously cached snapshot
}
c.attrsMu.Lock()
c.cachedAttrs = attrs
c.attrsMu.Unlock()
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.71930% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.28%. Comparing base (0460b40) to head (cc4b49c).
⚠️ Report is 346 commits behind head on main.

Files with missing lines Patch % Lines
pkg/sip/outbound.go 82.75% 2 Missing and 3 partials ⚠️
pkg/sip/inbound.go 92.85% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #775      +/-   ##
==========================================
+ Coverage   65.25%   66.28%   +1.03%     
==========================================
  Files          51       41      -10     
  Lines        6588     7997    +1409     
==========================================
+ Hits         4299     5301    +1002     
- Misses       1915     2206     +291     
- Partials      374      490     +116     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

LiveKit attributes are not mapped to SIP X-* headers when sending BYE

2 participants