In short
A UDS negative response is three bytes: 0x7F, the echoed service ID of the request that was rejected, and a negative response code (NRC) such as 0x31 requestOutOfRange, 0x33 securityAccessDenied or 0x78 responsePending. The NRC tells you why the ECU refused, and the echoed service ID tells you which request it refused; this is what the UDS NRC list on this page decodes.
You have an ECU on the bench, a tool window showing 7F 22 31, and a question that needs an answer in the next minute. This page gives the frame shape, then a lookup table of UDS negative response codes with the causes that produce them.
Every code and name below comes from two public open source implementations: the NRC reference module in py-uds and the ResponseCode class in python-udsoncan, both linked at the end and readable without a licence. ISO 14229-1 is a paid document, so nothing here quotes it. If your tool prints a name we do not list, check the py-uds NRC module first, which also covers the certificate and authentication codes this page does not reproduce, before treating it as supplier specific.
How to read a negative response: 0x7F, the echoed service ID, the NRC
The py-uds knowledge base gives the layout plainly. Byte 1 is the negative response service identifier, always 0x7F. Byte 2 is the service identifier of the rejected request. Byte 3 is the NRC. You send:
22 F1 90
That is service 0x22, ReadDataByIdentifier, asking for identifier 0xF190, which the udsoncan DataIdentifier table names VIN. The ECU replies:
7F 22 31
0x7F says this is a refusal. 0x22 says the refusal belongs to your ReadDataByIdentifier request. 0x31 is RequestOutOfRange: the ECU understood the service, accepted the message shape, and rejected the identifier you asked for.
Position decides the meaning, because 0x7F is both the negative response service identifier in byte 1 and a valid NRC in byte 3. A response of 7F 2E 7F is a refusal of service 0x2E with NRC 0x7F, ServiceNotSupportedInActiveSession, not a stutter.
The UDS NRC list, with real causes
Names and meanings follow the py-uds NRC reference module and the udsoncan ResponseCode class. The causes column is ours, drawn from bench work rather than from any document.
| Code | Name | What the ECU means | Common causes on the bench |
|---|---|---|---|
| 0x10 | GeneralReject | The requested action has been rejected by the server | The catch-all. A handler that failed without mapping the error to a specific code, an unhandled branch in the diagnostic application, or a supplier stack that returns this when nothing else fits. Treat it as a prompt to read the ECU log, not the bus |
| 0x11 | ServiceNotSupported | The server does not support the requested service | A mistyped service identifier, the wrong target ECU address, a request that landed on the gateway rather than the ECU behind it, or a service compiled out of this software variant |
| 0x12 | SubFunctionNotSupported | The server does not support the service specific parameters | The service exists but the sub-function byte does not: a session type this ECU does not implement, a reset type it does not offer, or a routine control sub-function outside its set |
| 0x13 | IncorrectMessageLengthOrInvalidFormat | The request length does not match the prescribed length, or the message format is invalid | A write payload with the wrong byte count, a missing sub-function byte, or transport padding counted as data. A conformant ISO-TP layer discards padding, so suspect the length byte before the padding itself |
| 0x14 | ResponseTooLong | The response would exceed the maximum number of bytes | Too many identifiers requested in one message, or a fault memory read whose filter matches far more records than the transport can carry |
| 0x21 | BusyRepeatRequest | The server is temporarily too busy | A polling loop with no gap between requests, a second tester competing for the same ECU, or an ECU in the middle of a long internal operation. Back off and retry rather than escalating |
| 0x22 | ConditionsNotCorrect | The server prerequisite conditions are not met | Ignition state, engine running or not running, supply voltage outside the accepted window, vehicle not stationary, or another operation already holding the resource you want |
| 0x24 | RequestSequenceError | The server expects a different sequence of request messages | A key sent without first requesting a seed, a data transfer started without its setup request, a routine stopped that was never started, or a half open sequence left behind by an earlier failure |
| 0x25 | NoResponseFromSubnetComponent | A subnet component did not respond within the specified time | The addressed server is fine but something behind it is not: an ECU on a sub-bus that is asleep or unpowered, a missing node on the bench harness, or an unterminated sub-bus |
| 0x26 | FailurePreventsExecutionOfRequestedAction | A failure condition prevents the requested action | An active fault the ECU treats as a blocker, or a degraded mode entered after an earlier failure. Clear or understand the fault first, then retry |
| 0x31 | RequestOutOfRange | A parameter attempts to substitute a value beyond its range | An identifier or routine the ECU does not implement, a value outside the permitted range, a length mismatch on a write, or an address outside the mapped range. See the dedicated section below |
| 0x33 | SecurityAccessDenied | The server’s security strategy has not been satisfied | No seed and key exchange completed, the wrong security level unlocked, or an unlock silently dropped by a session change or a session timeout |
| 0x34 | AuthenticationRequired | The client has insufficient rights based on its Authentication state | The ECU implements the Authentication service and expects it to be completed before this request. Present on newer platforms, absent on older ones |
| 0x35 | InvalidKey | The key sent did not match the key in the server’s memory | A wrong algorithm or constant, a byte order mismatch, or a key computed from a stale seed captured in an earlier attempt |
| 0x36 | ExceedNumberOfAttempts | Too many unsuccessful attempts to gain security access | A script retrying a wrong key in a loop. The counter usually survives longer than you expect |
| 0x37 | RequiredTimeDelayNotExpired | The latest security access attempt was initiated before the required timeout period | Retrying immediately after 0x36, or a client with no back-off. Some implementations persist the delay across a reset, so power cycling does not always clear it |
| 0x38 | SecureDataTransmissionRequired | The action must be sent over a secured communication channel | The request is legal but the channel is not. udsoncan’s ResponseCode.is_supported_by_standard() gates codes by standard version, which is why the same value can resolve to a different name depending on which edition your ECU was built against |
| 0x70 | UploadDownloadNotAccepted | An upload or download to server memory cannot be accomplished | A memory operation attempted outside the required session, a precondition routine that was never run, an address and length format the ECU does not accept, or a previous transfer that was never closed |
| 0x71 | TransferDataSuspended | A data transfer was halted due to a fault | A dropped block, a transport error mid-transfer, or a write error inside the ECU. The transfer must be restarted, not resumed |
| 0x72 | GeneralProgrammingFailure | The server detected an error while erasing or writing a memory location | A bad memory block, a supply dip during the operation, or a memory layout that does not match what the ECU expects |
| 0x73 | WrongBlockSequenceCounter | An error in the sequence of block sequence counter values | A retried block re-sent with an incremented counter, or a lost response that made the client repeat with the wrong counter. Almost always a client side bookkeeping bug |
| 0x78 | RequestCorrectlyReceived_ResponsePending | The action is not yet completed and the server is not yet ready | Not an error. A long routine, a memory erase or a self test is running. See the dedicated section below |
| 0x7E | SubFunctionNotSupportedInActiveSession | The sub-function is not supported in the currently active session | The sub-function exists, but not here. Usually a session that is more restricted than the one your test was written against |
| 0x7F | ServiceNotSupportedInActiveSession | The service is not supported in the currently active session | The service exists, but not in this session. The usual cause is a default session, either because the session change was never sent or because it timed out |
The 0x81 to 0x94 band: codes with a named precondition
Both libraries list a block of codes above 0x80 naming the exact vehicle condition that blocks the request. Getting one is good news, because it names what to change.
| Codes | What they name |
|---|---|
| 0x81, 0x82 | Engine speed above or below a preprogrammed threshold |
| 0x83, 0x84 | Engine running when it must not be, or not running when it must be |
| 0x85 | Engine run time below a preprogrammed limit |
| 0x86, 0x87 | Temperature above or below a preprogrammed threshold |
| 0x88, 0x89 | Vehicle speed above or below a preprogrammed threshold |
| 0x8A, 0x8B | Throttle or pedal position above or below a preprogrammed threshold |
| 0x8C, 0x8D | Transmission range not in neutral, or not in gear |
| 0x8F, 0x90, 0x91 | Brake switches not closed, shifter lever not in park, torque converter clutch locked |
| 0x92, 0x93 | Voltage above or below a preprogrammed threshold |
| 0x94 | A resource needed to supply the requested information is temporarily unavailable |
On a bench with no engine and no wheels, these usually mean a missing signal rather than a real condition. Restoring the residual bus simulation fixes more of them than any change to the request.
NRC 0x31 requestOutOfRange, in depth
Your message was well formed and the service is supported. What the ECU rejected is a parameter: py-uds puts it as a request containing a parameter that attempts to substitute a value beyond its range.
The four causes worth checking first
The table names them; this is what each looks like on a bench. A missing identifier usually came from a specification for a different variant, supplier or software version. An identifier that exists but not in the active session comes back as 0x31 rather than 0x7F on many stacks. A length mismatch on a write is 0x31 on some stacks and 0x13 on others. An address outside a mapped region gives 0x31 rather than a memory fault.
How to narrow it down
Read an identifier you are certain the ECU implements, such as 0xF190 for the VIN, in the same session and with no other change. A success proves the transport, the addressing and the session are alive, which isolates the failure to your identifier rather than the bench. It does not rule out the session cause, since VIN is readable where your identifier may not be. The second probe decides it: change to the extended session and repeat only the original request.
The other two need their own probes. For a length mismatch, read the identifier back and compare the returned byte count against what you wrote. For an address outside the mapped range, shorten the length or walk the address on the address based service.
NRC 0x22 conditionsNotCorrect, and its neighbours
0x22 says the request is acceptable but the ECU is not in a state to serve it. 0x31 is about what you sent, 0x22 about what the ECU is doing: a request that fails identically every time is 0x31 shaped, one that fails intermittently is 0x22 shaped. Its neighbours are not permission problems: 0x21 is load, so back off rather than escalate, and 0x24 is ordering, so replay the sequence from its first message.
The security related codes: 0x33, 0x35, 0x36 and 0x37
The table gives the causes; what it cannot show is the order they arrive in. 0x35 InvalidKey, 0x36 ExceedNumberOfAttempts and 0x37 RequiredTimeDelayNotExpired chain in that order: a wrong key, then a stop on attempts, then a delay you have to wait out. The length of that delay is defined by the ECU supplier, so it comes from your ECU specification. 0x33 stands apart, and its nastiest cause is a session timeout that drops the unlock while the bench looks idle.
Some implementations persist the attempt counter and the delay across a reset, so power cycling does not clear the state. And a test that retries a wrong key in a loop walks itself to a locked ECU in seconds. Put a hard attempt limit in the script.
NRC 0x78 is not a failure
0x78 is RequestCorrectlyReceived_ResponsePending: the ECU received a valid request, the work is not finished, and a real answer is still coming. It is flow control, not a refusal. The client is expected to keep waiting and to extend its response timeout each time one arrives, with the timing parameters taken from your ECU specification rather than from any web page, including this one.
Most 0x78 problems are client problems. A framework with a fixed short timeout gives up mid-sequence while the ECU is still working, which produces a stale response that lands during the next request and is misread as a fault there. If your logs show a failure followed by a response with the wrong echoed service identifier, look for an abandoned 0x78 sequence before it.
A six step triage for any NRC
- Confirm the echoed service identifier matches what you sent. A stale response, a second tester on the bus or a functionally addressed request several ECUs answered all put someone else’s byte 2 in front of you. Check it against our UDS services list with every service ID.
- Confirm the active session, and whether it timed out. Read it directly rather than trusting the last session change you sent. This resolves most 0x7F and 0x7E cases, where the service or sub-function exists but not in the session your test assumed. See our UDS sessions and security access article and, for the Ethernet connected case, Ethernet connected production tooling.
- Confirm the security access state. Check which level is unlocked, not merely that an unlock once succeeded, and whether step 2 invalidated it.
- Check the request length. Byte counts on writes and sub-function presence cover most 0x13 and a share of 0x31. Where padding is involved, suspect the ISO-TP length byte before the padding.
- Check the transport layer underneath. ISO-TP flow control on CAN, routing activation on DoIP, and on an Ethernet bench the wrong stream filtered, since diagnostic traffic shares the link with SOME/IP. If the problem is physical, put eyes on the bus with a scope on CAN FD, LIN, FlexRay and automotive Ethernet.
- Re-run with a raw capture alongside the tool log. The tool shows what it believes it sent, the capture shows what went out; when they disagree, everything upstream was wasted effort.
Where GSAS fits
GSAS Micro Systems is an engineering partner to validation and integration teams in India, and this is the class of problem our engineers spend real time on: getting from a stuck negative response code to a bench that reproduces it on demand, with a capture path that shows what the ECU received.
If your team is standing up a diagnostic bench or making an intermittent NRC reproducible, we are happy to talk it through. Our engineers work IST hours and quotations are issued in INR. Start with our automotive Ethernet capabilities, or request a consultation.
References
- py-uds, NRC reference module: uds.readthedocs.io/en/latest/autoapi/uds/message/nrc/index.html
- py-uds knowledge base, diagnostic message structure: uds.readthedocs.io/en/stable/pages/knowledge_base/diagnostic_message.html
- python-udsoncan documentation: udsoncan.readthedocs.io
- python-udsoncan,
ResponseCodeclass source: udsoncan.readthedocs.io/en/latest/_modules/udsoncan/ResponseCode.html - python-udsoncan,
DataIdentifiersource (VIN at 0xF190): github.com/pylessard/python-udsoncan - Scapy automotive layer, UDS negative response packet class: scapy.readthedocs.io/en/latest/layers/automotive.html
- can-isotp documentation, transport layer behaviour: can-isotp.readthedocs.io
- Wireshark UDS display filter reference: wireshark.org/docs/dfref/u/uds.html
- AUTOSAR Classic Platform standards, Diagnostic Communication Manager: autosar.org/standards/classic-platform
Also appears in:
Building for Automotive & Mobility?
Talk to our application engineers for personalized tool recommendations.
You might also like
View all →