Skip to main content
UDS negative response frame diagram showing 0x7F, original service ID and NRC, with common codes 0x31, 0x33 and 0x78, from GSAS Micro Systems India

UDS negative response codes: the complete NRC table with causes

GSAS Engineering · · 12 min read

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.

CodeNameWhat the ECU meansCommon causes on the bench
0x10GeneralRejectThe requested action has been rejected by the serverThe 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
0x11ServiceNotSupportedThe server does not support the requested serviceA 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
0x12SubFunctionNotSupportedThe server does not support the service specific parametersThe 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
0x13IncorrectMessageLengthOrInvalidFormatThe request length does not match the prescribed length, or the message format is invalidA 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
0x14ResponseTooLongThe response would exceed the maximum number of bytesToo many identifiers requested in one message, or a fault memory read whose filter matches far more records than the transport can carry
0x21BusyRepeatRequestThe server is temporarily too busyA 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
0x22ConditionsNotCorrectThe server prerequisite conditions are not metIgnition state, engine running or not running, supply voltage outside the accepted window, vehicle not stationary, or another operation already holding the resource you want
0x24RequestSequenceErrorThe server expects a different sequence of request messagesA 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
0x25NoResponseFromSubnetComponentA subnet component did not respond within the specified timeThe 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
0x26FailurePreventsExecutionOfRequestedActionA failure condition prevents the requested actionAn 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
0x31RequestOutOfRangeA parameter attempts to substitute a value beyond its rangeAn 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
0x33SecurityAccessDeniedThe server’s security strategy has not been satisfiedNo seed and key exchange completed, the wrong security level unlocked, or an unlock silently dropped by a session change or a session timeout
0x34AuthenticationRequiredThe client has insufficient rights based on its Authentication stateThe ECU implements the Authentication service and expects it to be completed before this request. Present on newer platforms, absent on older ones
0x35InvalidKeyThe key sent did not match the key in the server’s memoryA wrong algorithm or constant, a byte order mismatch, or a key computed from a stale seed captured in an earlier attempt
0x36ExceedNumberOfAttemptsToo many unsuccessful attempts to gain security accessA script retrying a wrong key in a loop. The counter usually survives longer than you expect
0x37RequiredTimeDelayNotExpiredThe latest security access attempt was initiated before the required timeout periodRetrying 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
0x38SecureDataTransmissionRequiredThe action must be sent over a secured communication channelThe 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
0x70UploadDownloadNotAcceptedAn upload or download to server memory cannot be accomplishedA 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
0x71TransferDataSuspendedA data transfer was halted due to a faultA dropped block, a transport error mid-transfer, or a write error inside the ECU. The transfer must be restarted, not resumed
0x72GeneralProgrammingFailureThe server detected an error while erasing or writing a memory locationA bad memory block, a supply dip during the operation, or a memory layout that does not match what the ECU expects
0x73WrongBlockSequenceCounterAn error in the sequence of block sequence counter valuesA 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
0x78RequestCorrectlyReceived_ResponsePendingThe action is not yet completed and the server is not yet readyNot an error. A long routine, a memory erase or a self test is running. See the dedicated section below
0x7ESubFunctionNotSupportedInActiveSessionThe sub-function is not supported in the currently active sessionThe sub-function exists, but not here. Usually a session that is more restricted than the one your test was written against
0x7FServiceNotSupportedInActiveSessionThe service is not supported in the currently active sessionThe 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.

CodesWhat they name
0x81, 0x82Engine speed above or below a preprogrammed threshold
0x83, 0x84Engine running when it must not be, or not running when it must be
0x85Engine run time below a preprogrammed limit
0x86, 0x87Temperature above or below a preprogrammed threshold
0x88, 0x89Vehicle speed above or below a preprogrammed threshold
0x8A, 0x8BThrottle or pedal position above or below a preprogrammed threshold
0x8C, 0x8DTransmission range not in neutral, or not in gear
0x8F, 0x90, 0x91Brake switches not closed, shifter lever not in park, torque converter clutch locked
0x92, 0x93Voltage above or below a preprogrammed threshold
0x94A 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 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

  1. 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.
  2. 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.
  3. Confirm the security access state. Check which level is unlocked, not merely that an unlock once succeeded, and whether step 2 invalidated it.
  4. 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.
  5. 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.
  6. 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

Building for Automotive & Mobility?

Talk to our application engineers for personalized tool recommendations.

Frequently asked questions

What does NRC 0x31 mean in UDS?
0x31 is RequestOutOfRange. The py-uds NRC reference describes it as a request message that contains a parameter attempting to substitute a value beyond its range. In practice the ECU understood the service and the message was well formed, but the identifier, routine, address or value you supplied is not one it accepts. The usual causes are an identifier the ECU does not implement, and an identifier that exists but not in the active session.
What is the difference between 0x31 requestOutOfRange and 0x22 conditionsNotCorrect?
0x31 is about the content of your request, 0x22 is about the state of the ECU. With 0x31 the parameter you sent is not one the server accepts, and sending the same request later changes nothing. With 0x22 the request itself is acceptable but a prerequisite is not met, so the same bytes can succeed once ignition, voltage, vehicle state or an in-progress operation changes. If a request fails identically forever, suspect 0x31 territory; if it fails intermittently, suspect 0x22.
Why does my ECU keep returning 0x7F with NRC 0x33?
0x33 is SecurityAccessDenied, which the py-uds reference describes as the server's security strategy not being satisfied by the client. The common causes are that no seed and key exchange has been completed, that you unlocked a different security level from the one this service needs, or that a session change or a session timeout silently dropped the unlock. Re-read the active session first, then re-run the unlock, then repeat the request without any gap.
Is NRC 0x78 an error?
No. 0x78 is RequestCorrectlyReceived_ResponsePending, described in the py-uds reference as the action not yet being completed and the server not yet being ready. The ECU is telling you it got a valid request and needs more time, typically for a long routine, a memory erase or a self test. The client is expected to keep waiting and extend its timeout while these keep arriving. A failure here is almost always the client giving up too early, not the ECU refusing.
What does NRC 0x24 requestSequenceError actually indicate?
0x24 is RequestSequenceError, described as the server expecting a different sequence of request messages. It means each individual request was legal but the order was not. Typical causes are sending a security key without first requesting a seed, starting a data transfer without the request that sets it up, stopping a routine that was never started, or resuming a multi-step exchange that an earlier failure left half open. Reset the ECU state and replay the sequence from its first message.
How long do I have to wait after NRC 0x37?
0x37 is RequiredTimeDelayNotExpired, described as the client's latest security access attempt being initiated before the server's required timeout period had elapsed. The length of that period is defined by the ECU supplier and is not a universal value, so it has to come from the ECU specification you were given. Some implementations also persist the delay across a reset, which is why power cycling the bench does not always clear it.
Where can I find a full list of UDS negative response codes?
The table on this page covers the common range you hit on a bench, built from two public open source references: the py-uds NRC module at uds.readthedocs.io and the ResponseCode class in python-udsoncan. The py-uds module also carries the certificate and authentication codes this page does not reproduce, so check it before treating an unfamiliar name as supplier specific. ISO 14229-1 is a paid document, so no free page can legitimately reproduce its text.
My ECU sends no response at all instead of an NRC, what does that mean?
Silence is not a negative response code, it is a transport or addressing problem one layer down. Either the request never reached the diagnostic application, or the reply never got back. Check the request and response identifier pair, the ISO-TP flow control frames on a CAN bench, and the routing activation state on a DoIP bench. Also check whether your client set the suppress positive response flag, because that makes a success silent by design.

Stay in the Loop

Get monthly compliance updates, product insights, and engineering best practices delivered to your inbox.