SIP Train Blog - SS7 and interworking
ISUP Cause Codes and Their SIP Equivalents: A Field Engineer's Guide to RFC 3398
If you have ever stared at a SIP trace from an interworking gateway and seen a 503 Service Unavailable come back from the far side, you have already met the lossy edge of the PSTN-to-SIP boundary. That 503 was almost certainly a Q.850 cause value on the TDM/SS7 side - congestion, temporary failure, or "network out of order" - that got squashed into a single SIP response code on its way out of the gateway. Without the right header, you have no way to tell which one.
This is the territory of RFC 3398 - ISUP to SIP Mapping - together with ITU-T Q.850 (the cause value definitions) and RFC 3326 (the SIP Reason header field). Read together, the three documents tell you exactly what the gateway is supposed to do, where the mapping is one-to-many and therefore lossy, and how to keep the original Q.850 cause visible end-to-end on the SIP side. If you work anywhere on the carrier-to-IP boundary - SBC, media gateway, hosted PBX trunk, IMS interconnect - this is the mapping that actually shows up in your traces.
The Q.850 cause value, briefly
A Q.850 cause information element carries four pieces of data: a coding standard (CCITT, ISO/IEC, national, or standard-specific), a location (where in the network the cause was generated - user, private network, public network local user, transit network, public network remote user, international network, network beyond interworking point), a cause class + cause value combined into a single 7-bit number, and a diagnostic field that some causes use for extra context (the rejected bearer capability, the offending invalid call reference, and so on).
The 7-bit cause value is what people loosely call "the cause code." Q.850 organises it by class, where the upper 3 bits give the class and the lower 4 the value within the class:
- Class 0 (causes 1-15) - normal events related to the called number itself: unallocated number, no route to destination, send special information tone, misdialled trunk prefix.
- Class 1 (causes 16-31) - normal call clearing events: normal clearing, user busy, no user responding, no answer from user, subscriber absent, call rejected, number changed.
- Class 2 (causes 32-47) - resource unavailable: no circuit available, network out of order, temporary failure, switching equipment congestion, access information discarded, requested circuit not available.
- Class 3 (causes 48-63) - service or option not available: quality of service unavailable, requested facility not subscribed, incoming calls barred, bearer capability not authorised, bearer capability not presently available.
- Class 4 (causes 64-79) - service or option not implemented: bearer capability not implemented, channel type not implemented, requested facility not implemented, only restricted digital information available, service or option not implemented unspecified.
- Class 5 (causes 80-95) - invalid message: invalid call reference, identified channel does not exist, suspended call exists but call identity does not, no call suspended, message type non-existent, mandatory information element missing.
- Class 6 (causes 96-111) - protocol error: information element non-existent, invalid information element contents, message not compatible with call state, recovery on timer expiry, parameter non-existent.
- Class 7 (causes 112-127) - interworking: interworking unspecified.
The class is what tells you "which kind of bad" before you even read the value. A cause 41 (temporary failure) and a cause 47 (resource unavailable, unspecified) are both class 2 - resource problem, not a routing problem and not a far-end refusal. A cause 21 (call rejected) and a cause 17 (user busy) are both class 1 - normal events, not a network or equipment problem. The class hint is useful when you are reading a trace that has been mangled into a generic SIP 503: if you can recover the Q.850 cause via the Reason header, the class alone often tells you whether to look at routing, the far-end subscriber, the network itself, or a service-policy decision.
The canonical ISUP → SIP mapping (RFC 3398 §7.2.4)
When a media gateway receives an ISUP REL (Release) message with a Q.850 cause and needs to terminate the SIP leg with an appropriate response, RFC 3398 §7.2.4 specifies which SIP response to use. The table below is the subset you will actually see in production traces - the full table covers every Q.850 cause but most of the rest are too rare to memorise.
| Q.850 cause | Description | SIP response | Notes |
|---|---|---|---|
| 1 | Unallocated number | 404 Not Found | The cleanest one-to-one mapping in the whole table. |
| 2 | No route to specified transit network | 404 Not Found | Usually surfaces in international interconnect. |
| 3 | No route to destination | 404 Not Found | |
| 16 | Normal clearing | (BYE) | Not a response - issued during the call, not at setup. |
| 17 | User busy | 486 Busy Here | |
| 18 | No user responding | 408 Request Timeout | The user agent didn't respond within timer T303/T310. |
| 19 | No answer from user (alerted) | 480 Temporarily Unavailable | The phone rang; the user didn't pick up. |
| 20 | Subscriber absent | 480 Temporarily Unavailable | Mobile-network roaming/registration variant of 19. |
| 21 | Call rejected | 603 Decline (or 403 Forbidden) | RFC 3398 prefers 603; some gateways emit 403. |
| 22 | Number changed | 410 Gone (or 301 Moved Permanently) | If the new number is supplied in the ISUP message, the gateway should use 301 with a Contact: header for the new destination. |
| 23 | Redirection to new destination | 410 Gone | |
| 26 | Non-selected user clearing | 404 Not Found | |
| 27 | Destination out of order | 502 Bad Gateway | The far-end exchange is unreachable, not absent. |
| 28 | Address incomplete | 484 Address Incomplete | Overlap-receive failure on the PSTN side. |
| 29 | Facility rejected | 501 Not Implemented | |
| 31 | Normal, unspecified | 480 Temporarily Unavailable | The lazy default. Whenever you see 31, suspect that a downstream switch had a more specific cause and dropped it. |
| 34 | No circuit/channel available | 503 Service Unavailable | Trunk-group congestion. |
| 38 | Network out of order | 503 Service Unavailable | |
| 41 | Temporary failure | 503 Service Unavailable | The most common "something failed and we didn't say what" cause. |
| 42 | Switching equipment congestion | 503 Service Unavailable | |
| 47 | Resource unavailable, unspecified | 503 Service Unavailable | |
| 55 | Incoming calls barred within CUG | 403 Forbidden | |
| 57 | Bearer capability not authorised | 403 Forbidden | |
| 58 | Bearer capability not presently available | 503 Service Unavailable | |
| 65 | Bearer capability not implemented | 488 Not Acceptable Here | The gateway can't carry the requested codec/capability. |
| 70 | Only restricted digital information bearer capability available | 488 Not Acceptable Here | |
| 79 | Service or option not implemented, unspecified | 501 Not Implemented | |
| 87 | User not member of CUG | 403 Forbidden | |
| 88 | Incompatible destination | 503 Service Unavailable | |
| 102 | Recovery on timer expiry | 504 Server Time-out | |
| 111 | Protocol error, unspecified | 500 Server Internal Error | |
| 127 | Interworking, unspecified | 500 Server Internal Error | The "I have no idea what just happened" cause. Frequently masks a downstream protocol error that nobody bothered to translate. |
Two patterns to commit to memory:
- Almost every "resource" cause (class 2) collapses to 503. Causes 34, 38, 41, 42, 47, 58, 88 - they all become 503. If you see a 503 from an interworking gateway, you know it was some class-2 cause; you do not know which without the
Reasonheader. - Almost every "service barred" or "not authorised" cause (class 3) collapses to 403. Causes 55, 57, 87 - they all become 403. Combined with the 503 collapse, these two facts mean a downstream gateway running RFC 3398 strictly will give you one of three responses (403, 488, or 503) for the entire class 2 + class 3 + class 4 range, with the genuine cause buried in a header.
The other direction: SIP → ISUP (RFC 3398 §8)
When a SIP-originated call needs to be terminated into an ISUP trunk and a SIP failure response arrives, the gateway has to map the SIP response code back to a Q.850 cause to put in the ISUP REL. The mapping is documented in RFC 3398 §8.2.1; here is the practical subset:
| SIP response | Q.850 cause | Notes |
|---|---|---|
| 400 Bad Request | 41 (Temporary failure) | |
| 401 Unauthorized | 21 (Call rejected) | |
| 403 Forbidden | 21 (Call rejected) | |
| 404 Not Found | 1 (Unallocated number) | |
| 405 Method Not Allowed | 63 (Service/option unavailable, unspecified) | |
| 406 Not Acceptable | 79 (Service or option not implemented) | |
| 407 Proxy Authentication Required | 21 (Call rejected) | |
| 408 Request Timeout | 102 (Recovery on timer expiry) | |
| 410 Gone | 22 (Number changed) - without diagnostic | |
| 413 Request Entity Too Large | 127 (Interworking) | |
| 414 Request-URI Too Long | 127 (Interworking) | |
| 415 Unsupported Media Type | 79 (Service or option not implemented) | |
| 416 Unsupported URI Scheme | 127 (Interworking) | |
| 420 Bad Extension | 127 (Interworking) | |
| 480 Temporarily Unavailable | 18 (No user responding) | |
| 481 Call Leg/Transaction Does Not Exist | 41 (Temporary failure) | |
| 482 Loop Detected | 25 (Exchange routing error) | |
| 483 Too Many Hops | 25 (Exchange routing error) | |
| 484 Address Incomplete | 28 (Address incomplete) | |
| 485 Ambiguous | 1 (Unallocated number) | |
| 486 Busy Here | 17 (User busy) | |
| 487 Request Terminated | (no mapping - call cancelled) | The originating side sent CANCEL before the call was answered; on the ISUP side the gateway sends REL with cause 16 (normal clearing) or no cause if the call was never answered. |
| 488 Not Acceptable Here | 31 (Normal, unspecified) | |
| 500 Server Internal Error | 41 (Temporary failure) | |
| 501 Not Implemented | 79 (Service or option not implemented) | |
| 502 Bad Gateway | 38 (Network out of order) | |
| 503 Service Unavailable | 41 (Temporary failure) | |
| 504 Server Time-out | 102 (Recovery on timer expiry) | |
| 505 Version Not Supported | 127 (Interworking) | |
| 580 Precondition Failure | 47 (Resource unavailable, unspecified) | |
| 600 Busy Everywhere | 17 (User busy) | |
| 603 Decline | 21 (Call rejected) | |
| 604 Does Not Exist Anywhere | 1 (Unallocated number) | |
| 606 Not Acceptable | 31 (Normal, unspecified) |
The SIP-to-ISUP direction is also lossy - 403 collapses to cause 21, 404 collapses to cause 1, 503 collapses to cause 41. If you have a SIP origination that the user wants you to debug and the only artefact is the ISUP REL the far side reports having received, you cannot reliably reconstruct the original SIP failure. (You can sometimes infer it from the location code, but the cause value alone is not enough.)
The Reason header: how to keep the original cause visible (RFC 3326)
The lossiness of the basic mapping is exactly why RFC 3326 exists. The Reason header field carries a structured cause description through the SIP signalling, with both Q.850 and SIP namespaces, so a downstream proxy or B2BUA can read the original Q.850 cause even when the SIP response code itself has been compressed.
Two examples - first the ISUP-originated direction:
SIP/2.0 503 Service Unavailable
Via: SIP/2.0/UDP gw1.example.net:5060;branch=z9hG4bK-abc
From: <sip:+15551234567@example.net>;tag=A1
To: <sip:+15559876543@example.net>;tag=B2
Call-ID: 9c0e3a@example.net
CSeq: 1 INVITE
Reason: Q.850 ;cause=42 ;text="switching equipment congestion"
Content-Length: 0
The basic SIP response is 503 per RFC 3398 §7.2.4. The Reason header preserves the actual Q.850 cause (42 - switching equipment congestion), so an upstream node can distinguish congestion from temporary failure or no-circuit-available even though the response code is the same in all three cases.
Second example - the SIP-originated direction with a CANCEL:
CANCEL sip:+15551234567@example.net SIP/2.0
Via: SIP/2.0/UDP ua1.example.net:5060;branch=z9hG4bK-xyz
From: <sip:+15559876543@example.net>;tag=A1
To: <sip:+15551234567@example.net>
Call-ID: 9c0e3a@example.net
CSeq: 1 CANCEL
Reason: SIP ;cause=200 ;text="Call completed elsewhere"
Content-Length: 0
This is the canonical use of the SIP namespace inside the Reason header. The cancel reason cause=200 ;text="Call completed elsewhere" (RFC 3326 §3) lets parallel-fork participants distinguish "the originator got bored and hung up" from "another fork already won the race" - useful when the surviving SIP UA needs to render a sensible call log.
A few practical points about Reason:
- It is informational, not authoritative. The basic SIP response code still drives transaction matching, retry behaviour, and fallback routing on every intermediate node.
Reasonis a hint for human operators and for billing/CDR systems. - Multiple
Reasonheaders are allowed. A response can carry both aReason: Q.850 ;cause=Nand aReason: SIP ;cause=Nsimultaneously when an interworking gateway wants to surface both views. - It survives a fair number of B2BUAs unchanged. Sensible SBC implementations propagate
Reasonend-to-end. Less sensible ones strip it. If you are debugging through an unknown SBC and theReasonis missing, capture on both legs to confirm which node is responsible.
SIP-T and SIP-I: full ISUP encapsulation (RFC 3372 / RFC 3204)
For carrier-grade interconnect - particularly for tandem switches that need to preserve the entire original ISUP signalling end-to-end across a SIP transit - RFC 3398's cause-and-Reason mapping is not enough. The full ISUP message has fields (calling-party category, transit network selection, charge information, generic numbers, redirection counter) that no SIP header captures. The solution is SIP-T (RFC 3372 - Session Initiation Protocol for Telephones (SIP-T): Context and Architectures), which uses the application/ISUP MIME type registered by RFC 3204 (MIME Media Types for ISUP and QSIG Objects) carried inside a multipart/mixed body (RFC 2046) alongside the SDP.
A typical SIP-T INVITE looks like this in outline:
INVITE sip:+15551234567@gw1.example.net SIP/2.0
...
Content-Type: multipart/mixed; boundary="boundary42"
--boundary42
Content-Type: application/sdp
v=0
o=user1 53655765 2353687637 IN IP4 198.51.100.10
...
--boundary42
Content-Type: application/ISUP; version=itu-t92+; base=itu-t92+
Content-Disposition: signal; handling=optional
... raw binary ISUP IAM ...
--boundary42--
SIP-I is the ITU-T variant of the same idea (Q.1912.5), and is the form used in IMS interconnect. Both rely on RFC 3204's MIME registration; the differences between them are mostly in which ISUP variant is encapsulated and how strictly the gateway is required to render the full ISUP into SIP headers in addition to attaching the body. For our purposes - a field engineer reading a trace - the key fact is that when a tandem-grade gateway carries SIP-T or SIP-I, you can decode the embedded ISUP message directly in Wireshark (which has an ISUP dissector), and you do not have to rely on the cause-mapping summary in the SIP response. The original Q.850 cause is right there in the encapsulated REL.
The reverse is not true: an originating SIP UA does not generally produce an ISUP body. SIP-T is a transit feature, not a UA feature. So you will see SIP-T bodies on call legs that traverse a class-4 tandem and not on legs that originate from a UCaaS softphone.
What to look for in a real trace
A few patterns from production capture review that go directly to the mapping:
- A response of
503 Service Unavailablewith noReasonheader from a media gateway. The gateway is RFC 3398-compliant on the basic mapping but is not emittingReason. You have lost the original Q.850 cause. If this is happening repeatedly, the gateway'sReasonemission is misconfigured, or it is sitting behind an SBC that stripsReason. - A response of
480 Temporarily UnavailablewithReason: Q.850 ;cause=31. The downstream switch had no specific information; it sent cause 31 (normal, unspecified) and the gateway dutifully mapped 31 to 480. There is no useful information here. Treat it as a black box and look at the next hop downstream. - A
486 Busy HerewithReason: Q.850 ;cause=17from a call to a mobile. Real busy. The mobile network reported the subscriber on a call. (Distinguish from cause 18/19 - those are alerted/no-answer, mapped to 408 and 480.) - A
503 Service UnavailablewithReason: Q.850 ;cause=34. Trunk congestion at a specific exchange. If you see this clustered in time-of-day patterns, it is a sized-trunk capacity issue, not a fault. - A
503 Service UnavailablewithReason: Q.850 ;cause=42. General switching equipment congestion. Different from cause 34 (which is specific to the trunk group); cause 42 is exchange-wide. Larger problem. - A
404 Not FoundwithReason: Q.850 ;cause=1for a number you know exists. The originating side number-translation failed before the call hit the destination exchange. Look at the dial-plan / least-cost-routing on the originating gateway. - A
403 ForbiddenwithReason: Q.850 ;cause=21. The far end actively rejected the call. Different from cause 17 (busy) - cause 21 is "this user does not want this call right now." Frequent in nuisance-call-blocker deployments. - A
500 Server Internal ErrorwithReason: Q.850 ;cause=127. Interworking, unspecified - the maximum-uncertainty cause. The downstream gateway encountered something it couldn't map cleanly. The cause carries no diagnostic value; you have to capture upstream.
The general rule: always read Reason first. If Reason is present, the basic SIP response code is for the protocol machinery; the Reason is for you. If Reason is missing on an interworking call, that is itself a finding - capture both legs and confirm which node stripped it.
Closing the loop
ISUP-to-SIP mapping is one of those pieces of carrier engineering that nobody is taught and everybody is expected to know. Engineers who can read both directions of the table fluently - who know that a 503 is class 2 of something, that a Reason: Q.850 ;cause=42 is exchange congestion not trunk congestion, and that a SIP-T body on a transit leg can be decoded directly in Wireshark - diagnose carrier interconnect problems in minutes that would take an hour for an engineer working from the SIP side alone.
SIP Train's SIPT-301 - SS7, SIGTRAN, and Legacy Interworking course (the first course on the CCVE certification track) covers RFC 3398, Q.850, RFC 3326 (Reason), and the SIP-T/SIP-I encapsulation pattern in full detail, with annotated traces from carrier interconnect, IMS interconnect, and hosted-PBX trunk scenarios. If your work crosses the PSTN-to-IP boundary - and most carrier and UCaaS engineering does - SIPT-301 is built for you.
SIPT-301 covers ISUP-to-SIP, Q.850, and SIP-T/SIP-I in depth
SS7, SIGTRAN, and Legacy Interworking is the first course on the CCVE certification track. It covers RFC 3398, Q.850, RFC 3326, and the SIP-T/SIP-I encapsulation pattern in full detail, with annotated traces from carrier interconnect, IMS interconnect, and hosted-PBX trunk scenarios. If your work crosses the PSTN-to-IP boundary, this is the course built for you.
Browse the catalog View pricing