SIP 488 Not Acceptable Here
Short version: 488 is a verdict on the SDP, not on the call. Something in the offer was unusable at that particular endpoint — usually the codec list, the payload-type mapping, or the transport profile. Read the last offer sent before the 488, not the 488 itself.
What the response actually means
RFC 3261 defines 488 as "some aspect of the session description or the Request-URI is not acceptable here" — at this resource, right now. The "here" is load-bearing: it is the reason 488 exists separately from 606 Not Acceptable, which is the same rejection made on behalf of the user everywhere rather than at one device.
In practice, in ninety-odd percent of traces, 488 means the RFC 3264 offer/answer
exchange failed: the answerer could not construct an answer it was prepared to use.
Do not confuse it with 415 Unsupported Media Type, which is about the body's
content type (the far end could not parse or would not accept
application/sdp, or choked on a multipart body), not about its contents.
Read the Warning header first
Many implementations attach a Warning header to the 488, and the
three-digit warn-code narrows the search enormously:
304media type not available — them=line itself (audio, video, image) was unwanted.305incompatible media format — the classic "no codec in common".306/307attribute or session description parameter not understood — ana=line the far end rejected rather than ignored.300/301/302incompatible network protocol, address format or transport — IPv4 versus IPv6, or RTP/AVP versus RTP/SAVP.370insufficient bandwidth — usually ab=line or a policy limit.399miscellaneous — the vendor could not be bothered, but the free text after it is often specific and worth reading.
What actually causes it
No codec in common
The default suspicion, and it is right often enough. One side offers G.729 only,
the other has PCMA/PCMU only, and there is no transcoding licence in between — or
there is a transcoder, but the call is taking a path that bypasses it. The tell is
that the two m=audio payload-type lists have an empty intersection once
you exclude telephone-event and comfort noise, which are not media in
their own right and cannot carry the call on their own.
The codec matches but the payload type does not
Dynamic payload types (96–127) are chosen per direction, and strictly speaking each
side may number them as it likes. Plenty of equipment is not that liberal. The usual
casualty is RFC 4733 telephone-event at PT 101 on one leg and 96 on the
other, or an a=fmtp:101 0-15 against 0-16. An SBC that
renumbers one leg and forwards the other unchanged produces exactly this.
Secure versus clear media
An offer with m=audio ... RTP/SAVP and a=crypto lines
arriving at a leg configured for plain RTP/AVP is unanswerable, and vice
versa. Even when both sides do SRTP, the SDES crypto suites have to intersect —
AES_CM_128_HMAC_SHA1_80 against a peer offering only
..._32 fails the same way. DTLS-SRTP
(UDP/TLS/RTP/SAVP) offered to an SDES-only box is a third variant of the
same mismatch.
A T.38 re-INVITE the carrier will not take
Fax calls answer in G.711, then the terminating gateway detects CNG/CED and sends a
re-INVITE switching to m=image ... udptl t38. If the trunk does not
support T.38, that re-INVITE comes back 488. This is normal and survivable — the
gateway is supposed to fall back to G.711 pass-through — but many do not, and the fax
dies while the voice call would have been fine. If your 488 happens two to five
seconds after answer on a fax number, this is what you are looking at.
An extra media line
Offering video, BFCP or MSRP to a box that handles audio only should produce an answer
with that m= line zeroed, not a rejection of the whole session. Not every
implementation does the polite thing. The same applies to unexpected
a= attributes: ICE, rtcp-mux and bundle attributes are
supposed to be ignored when unsupported.
What to check in the trace
- Find the last SDP offer before the 488, and confirm which direction it travelled. The 488 answers whoever sent that offer.
- Diff the two
m=lines and theira=rtpmap/a=fmtpsets side by side. Codec names, payload numbers and fmtp parameters — all three. - Compare the transport profile token on the
m=line, and the presence or absence ofa=crypto. - Read the
Warningheader, and any body on the 488: a helpful implementation returns its own capabilities as SDP. - Establish whether the SBC generated the 488 itself or relayed it. A 488 that appears on the ingress leg with no matching failure on the egress leg was made locally, which points at your codec policy rather than the carrier's.
- If it is a re-INVITE, check what changed against the original offer. Very often exactly one thing did, and that thing is the answer.
Two nuances worth knowing
A 488 to a re-INVITE does not end the call. RFC 3261 is explicit that when a re-INVITE fails, the session parameters stay as they were, as if it had never been sent. If the call dropped anyway, something above the transaction layer decided to drop it, and that decision is a separate finding.
In a delayed-offer call — an INVITE with no SDP — the offer arrives in the 200 OK and
the answer goes in the ACK. There is no response code left to reject with, so the same
negotiation failure surfaces as an immediate BYE, often carrying a
Reason header, a second or two after answer. If you are hunting a codec
problem and cannot find a 488, look for that BYE.
hiccup diffs the two legs of an SBC call automatically and reports codec lists that narrowed, payload types that were renumbered and crypto lines that appeared or vanished — as findings, next to the ladder. Self-hosted, free for individual users.
upload a trace