SIP 488 Not Acceptable Here: Find the Rejected SDP Line
SIP 488 Not Acceptable Here means the far end, or Asterisk itself, understood your INVITE but rejected the SDP offer: no common codec, an RTP/SAVP versus RTP/AVP mismatch, or a broken media line. Read the SDP in a capture to see which.
- A 488 is a media negotiation failure, not an authentication or routing failure, so the answer is always in the SDP body and the Warning header.
- Compare the source IP of the 488 with your PBX and trunk addresses to learn whether the provider or Asterisk rejected the call.
- The m= line profile (RTP/AVP vs RTP/SAVP) and the payload list after it identify encryption and codec mismatches in seconds.
- Fix codecs on the trunk endpoint (disallow=all, then allow=ulaw,alaw) and set media_encryption to match what the provider accepts, then reload.
- Verify with a fresh test call: the 200 OK SDP should list one codec plus telephone-event, and pjsip show channelstats should show RTP flowing both ways.
What does SIP 488 Not Acceptable Here mean?
A 488 is a 4xx client-error final response. The INVITE was parsed and the request itself is fine, but the session description (SDP) in it cannot be accepted. Authentication, routing and dialplan are not the problem, which is why the failure is usually instant: no ringing, no early media.
The response often carries a Warning header that tells you which part of the SDP failed. These codes come from the SIP specification and are the fastest clue:
| Warning header | Meaning | Usual cause |
|---|---|---|
| 301 Incompatible network protocol | Transport in the m= line not supported | Offering RTP/SAVP, UDPTL or another profile the far side lacks |
| 302 Incompatible network address formats | Address type not supported | IPv6 in c= line to an IPv4-only peer |
| 304 Media type not available | Media type not supported | Video m= line, or T.38 image stream, rejected |
| 305 Incompatible media format | No codec in common | Offered payload list does not overlap the far side's list |
| 306 Attribute not understood | An a= line was refused | Unsupported crypto suite or odd attribute |
| 307 Session description parameter not understood | Other SDP parameter refused | Bad ptime, malformed c= line |
How do I tell who sent the 488: the provider or Asterisk?
Look at the source IP of the 488 packet. If it comes from the trunk's IP, the provider rejected your offer. If the 488 is generated locally, it is sent from the PBX itself (or you see it on an internal leg), and the Asterisk log typically contains messages about no compatible codecs or a failed SDP negotiation.
This matters because the fix differs. A provider 488 means changing what you offer. A local 488 means Asterisk could not build an answer from what the caller offered versus what the endpoint allows, so you change the endpoint or add transcoding.
How do I capture the INVITE and the 488?
Turn on SIP message logging and watch one failing call. Do this on a quiet system, because logger output is verbose and SDP can reveal internal addresses.
asterisk -rvvv
pjsip set logger on
pjsip set history on
core set verbose 5
core set debug 3
# independent capture, run from the shell
tcpdump -i any -s 0 -w /tmp/488.pcap port 5060
# or interactive ladder view with SDP
sngrep -d any port 5060How do I read the SDP in a SIP INVITE?
Each SDP line is type=value. Only a few lines decide whether a 488 happens. Read the m= line first, then the attributes beneath it.
| SDP line | What to check | Points to |
|---|---|---|
| m=audio 12000 RTP/AVP 0 8 101 | Profile and payload list | RTP/AVP is plain RTP; the numbers are the codecs offered, in preference order |
| m=audio 12000 RTP/SAVP ... | SAVP profile | SRTP offered; far side may only accept RTP/AVP |
| a=rtpmap:8 PCMA/8000 | Payload to codec map | 0 PCMU, 8 PCMA, 9 G722, 18 G729, 101 telephone-event; 96 and above are dynamic (Opus is usually 96-127) |
| a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:... | SDES key | SRTP via SDES |
| a=fingerprint / a=setup | DTLS key | DTLS-SRTP, normally WebRTC |
| c=IN IP4 10.0.0.5 | Media address | Private IP behind NAT, or 0.0.0.0, or missing |
| a=sendrecv / a=inactive | Direction | inactive on a first INVITE is unusual and may be refused |
| a=ptime:20 | Packetization | Odd values (such as 10 or 60) can be rejected |
| m=video ... / m=image ... udptl | Extra streams | Video or T.38 where only audio is accepted |
Worked example: codec mismatch and its fix
Here Asterisk offers only G.722 and telephone-event. The trunk supports only G.711, so it rejects the call:
--> INVITE sip:15551234567@sip.carrier.example SIP/2.0
m=audio 12844 RTP/AVP 9 101
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
c=IN IP4 203.0.113.10
<-- SIP/2.0 488 Not Acceptable Here
Warning: 305 sip.carrier.example "Incompatible media format"
# after the fix (offer 0 8 101), the answer is:
<-- SIP/2.0 200 OK
m=audio 30112 RTP/AVP 0 101
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
c=IN IP4 198.51.100.20 Codec and SRTP mismatches: how to fix them
For codecs, the offer must contain at least one payload the trunk supports. Set it explicitly on the trunk endpoint. G.729 only works if you have a licensed codec (codec_g729a or a hardware or license solution), and most carriers do not accept Opus, so ulaw and alaw are the safe default.
For encryption, match the m= profile to the provider. If the provider answers 488 to RTP/SAVP, turn SRTP off. If it requires SRTP and you offer RTP/AVP, the rejection comes the other way. SDES (media_encryption=sdes) only protects keys if signaling runs over TLS, since a=crypto keys travel in clear text inside the SDP otherwise.
DTLS-SRTP (media_encryption=dtls) needs additional certificate and verification options on the endpoint, such as dtls_cert_file, dtls_verify and dtls_setup. Check the option names against the pjsip_configuration.txt or sample pjsip.conf shipped with your Asterisk version before using them.
; pjsip.endpoint_custom.conf or the trunk endpoint
[carrier-trunk]
type=endpoint
disallow=all
allow=ulaw,alaw
media_encryption=no ; or sdes (TLS transport) / dtls
dtmf_mode=rfc4733
direct_media=noOther SDP problems: NAT addresses, video, T.38 and bridged-leg 488s
If codecs and profile match, check the c= line. A private address such as 10.x in a call to a provider means NAT is not handled, and some carriers reject it. On the PJSIP transport set external_media_address, external_signaling_address and local_net; on the endpoint set rtp_symmetric=yes, force_rport=yes and rewrite_contact=yes. Disable SIP ALG on the router, because it rewrites SDP and can leave a malformed or mismatched c= line.
If the 488 appears when Asterisk bridges two legs, the caller's codecs and the trunk's codecs have no overlap and no translation path exists. Check with core show translation and core show codecs, and confirm the codec modules are loaded with module show like codec. For video m= lines, set disallow=all then allow=ulaw,alaw only (no video codecs) on the trunk. For T.38 rejections, set t38_udptl=no on the endpoint to stop the re-INVITE.
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
external_media_address=203.0.113.10
external_signaling_address=203.0.113.10
local_net=192.168.0.0/16 Verify the fix and avoid common mistakes
Reload, then place a fresh test call and watch the SIP trace.
Frequent mistakes: allowing codecs on the extension but not on the trunk; leaving SRTP enabled from a template; forgetting to reload; testing with a softphone that offers different codecs than the real phone; and SIP ALG still active.
- Reload: pjsip reload for hand edits, or fwconsole reload in FreePBX.
- Run pjsip show endpoint carrier-trunk and confirm the allow list and media_encryption value.
- Place an outbound test call with pjsip set logger on and confirm the 200 OK SDP lists one codec plus telephone-event.
- During the call run core show channels, then core show channel <name> to see the negotiated read and write formats, and pjsip show channelstats to confirm packets in both directions.
- Confirm two-way audio and test a DTMF digit.
Common questions
Is a SIP 488 the same as a 606 Not Acceptable?
No. A 488 rejects the request on this particular path, usually because of the SDP, and another route or different offer may work. A 606 is a global failure meaning the user cannot accept the session anywhere.
Why do I get 488 only on outbound calls and not inbound?
Outbound calls make your PBX build the SDP offer, so your codec and encryption settings are judged by the provider. On inbound calls the provider offers and Asterisk answers from its allowed list, which is often more lenient.
Can a 488 be caused by DTMF settings?
Rarely. A telephone-event payload (101) that the far side does not support is usually ignored, but a malformed a=fmtp line for it can be refused. Set dtmf_mode=rfc4733 and keep the payload at 101.
Does enabling transcoding fix a 488 on the trunk?
Only when the two bridged legs lack a common codec. If the trunk itself supports only G.711, Asterisk must offer ulaw or alaw to it and translate from the caller's codec, so the trunk endpoint still has to allow them.
Why does the 488 show in FreePBX even though codecs look right?
Check the endpoint that actually handled the call, with pjsip show endpoint, because FreePBX can apply codecs per trunk and per extension separately. Also check that media_encryption was not inherited as sdes or dtls.