In SIP, what's negotiated isn't what's supported
Three trunks that refused to place a call between two vendors. In all three, a peer signaled one thing and did another.
A SIP trunk that works in the lab can break in production as soon as it joins two devices from different vendors. Every time this happened to me, the cause was the same: a peer that signals a capability, a role, or a format, and then does something else. Both implementations can be defensible and still diverge.
The three cases below are real, and in all three the trunk refused to place a call. The fix was on the SBC every time, never on the misbehaving device across the trunk.
| What's negotiated | What the peer actually does | Result |
|---|---|---|
| UPDATE sent | UPDATE out of sequence, offer not yet resolved | Ignored, retransmitted in a loop, no calls |
refresher=uac | The UAC never refreshes | Call dropped when the timer expires |
| Early Offer expected | The SBC sends Delayed Offer | Call rejected |
Case 1: an UPDATE no one was allowed to send
Across the trunk I had a Cisco CUBE, and on my side an AudioCodes SBC. The symptom was easy enough to observe, since no call went through at all.
The trace gave the answer: the CUBE was sending an UPDATE while the SDP offer from the initial INVITE had not yet received its answer. RFC 3311 forbids it, because you do not start a new offer/answer negotiation while the first one is unresolved. AudioCodes was doing exactly what the RFC asks, and ignored the UPDATE without replying.
The CUBE, which therefore never got an answer, retransmitted in a loop. The behavior repeated on every call and the trunk stayed down.
The fix was to disable UPDATE on the SBC: the initial negotiation then completes normally and the call goes through.
The compliant peer in this case was AudioCodes, which followed the RFC to the letter, and that did not keep the trunk up. What brought it down was not a fault in the protocol sense, but the gap between what the CUBE sent and what AudioCodes tolerated.
Case 2: a refresher that never refreshes
My SBC was facing an Alcatel-Lucent OXE, the OmniPCX Enterprise, and calls kept dropping systematically, always at the same point.
RFC 4028 session timers exist to clear dead calls. Both sides negotiate a Session-Expires and name a refresher, the one that will periodically send a re-INVITE or an UPDATE to signal the call is alive.
Session-Expires: 1800;refresher=uac
The designated refresher was the UAC, and that UAC never refreshed. When the timer expired no one had shown a sign of life, so the call was declared dead and cut while media was flowing both ways.
The fix was to move the refresh to the UAS side, so the role went to the party that actually performs it, and calls stopped dropping.
Negotiating a role did not guarantee it would be honored: refresher=uac was a promise the UAC did not keep, and the SBC reassigned it to a peer that did.
Case 3: Early Offer, or nothing
An AudioCodes SBC was sending Delayed Offer while the IPBX across the trunk required Early Offer, and the call was rejected on the spot.
Two ways to present the SDP:
Early Offer : INVITE + SDP
Delayed Offer : INVITE without SDP, then SDP in the 200 OK
Both forms are valid, but not every device handles both. This IPBX wanted the offer in the INVITE and refused an INVITE with no SDP.
The fix was to reconfigure the SBC to send Early Offer, using the Delayed to Early Offer conversion on AudioCodes. The IPBX then got what it expected and the call set up.
Valid per the RFC did not mean accepted by the peer, since the Delayed Offer was legitimate and rejected anyway. The SBC adapted the format to what the other side could read.
What these three cases share
In all three, one side signaled one thing and did another: an UPDATE out of sequence, a refresher named but idle, an Early Offer expected against a Delayed Offer sent. Two compliant implementations can still refuse to talk.
I take two reflexes out of this.
The first is that I don't fix the vendor across the trunk. I patched neither the CUBE, nor the OXE, nor the IPBX, and all three fixes were configurations on the SBC, which is the layer where you absorb the peer's reality.
The second is that I trust the trace. The vendor doc says what the device is supposed to do, the SIP capture says what it does, and the two don't always agree. Facing a trunk that refuses to work, I capture rather than read a datasheet, I compare what's negotiated to what happens, and I adapt on the SBC.
A trunk breaking between two vendors, an SBC migration, a go-live stuck on signaling? Get in touch.
Field note by qaryon
Nicolas Marxer
Enterprise communications solution architect focused on operator, integrator, and B2B deployments.
Need a field view on your communications architecture?
Audit, scoping, or deployment: I work directly on UCaaS, CCaaS, IPBX, SBC, automation, and applied AI.
Discuss a telecom projectRelated reading
On a SIP trunk, security is not a deployment option, it is a contractual responsibility
Toll fraud, STIR/SHAKEN, mTLS, SBC hardening. What protects a SIP trunk in 2026, layer by layer, with the configurations and the checklist.
Isolating a VoIP datacenter in broad daylight, without dropping a call
Working on a datacenter during business hours without cutting a customer. The drain runs through DNS, not the SBC: pull the IP, let sessions finish, restore by mirroring. The real trap is the TTL.
I don't automate the decision, I automate the fact that it expires
A CVE lands on a component you run. The faulty dependency was fixed upstream weeks ago, but the image publisher never rebuilt. You can't patch, you can't ship, and you can't forget. What happens next doesn't delegate to a model, and it's the best explanation I know of what AI cannot do.