SMPP Error Codes Explained
What the common SMPP command_status values actually mean, which ones are your fault, which are the supplier's, and what to do about each.
When an SMPP submit fails, the SMSC returns a command_status value in the submit_sm_resp PDU. Those values are defined in the SMPP specification, and most integration problems are one of about a dozen of them. Knowing which are your fault and which are the supplier’s saves a great deal of time.
How to read a command_status
The value is a four-byte integer, usually written in hex. 0x00000000 is ESME_ROK, the SMSC accepted the submission. Anything else is a rejection, and the message never entered the network.
Two things to keep straight. First, a successful submit_sm_resp means accepted for delivery, not delivered, delivery is reported later in a receipt. Second, values from 0x00000400 upward are vendor-specific, so a code in that range needs your supplier’s documentation rather than the specification.
Bind and session errors
0x0000000D ESME_RBINDFAIL, the bind was rejected. Usually credentials, but also a system_id already bound elsewhere, or an address_range mismatch. Check whether you are exceeding your permitted number of concurrent binds before assuming the password is wrong.
0x0000000E ESME_RINVPASWD and 0x0000000F ESME_RINVSYSID, wrong password, wrong system_id. Note that some SMSCs deliberately return the generic bind failure instead, to avoid confirming which half is correct.
0x00000005 ESME_RALYBND, already bound. Your client is attempting a second bind on a session that is already established, typically after a reconnect where the old session was not cleanly closed.
0x00000004 ESME_RINVBNDSTS, the command is not valid for this bind type. Sending a submit_sm on a receiver-only bind produces this.
Addressing errors
0x0000000B ESME_RINVDSTADR, invalid destination address. Almost always a formatting problem on your side: missing country code, a leading plus where the SMSC wants international format without one, or a mismatch between the number and the ton/npi values you set. Fix the number format before escalating.
0x0000000A ESME_RINVSRCADR, invalid source address. Your sender ID is malformed for the configured type: too long for alphanumeric, non-numeric characters where a numeric address is expected, or an unregistered sender ID on a route that requires registration.
Content errors
0x00000001 ESME_RINVMSGLEN, invalid message length. The payload exceeds what the field allows. Long messages need either concatenation via UDH or the message_payload optional parameter; check which your supplier expects.
0x00000003 ESME_RINVCMDID, the SMSC does not support the operation you sent. Common when using data_sm against a platform that only accepts submit_sm.
0x00000067 ESME_RINVDCS, invalid data coding scheme. Usually a wrong value for Unicode. UCS-2 is normally 0x08; sending Unicode content with a GSM-7 DCS produces unreadable messages when it does not produce this error.
Throttling and capacity
0x00000058 ESME_RTHROTTLED; you are submitting faster than the bind permits. This is the healthy way for a platform to push back. Back off, retry with a delay, and treat a sustained rate of these as a signal to review your provisioned TPS rather than to retry harder.
0x00000014 ESME_RMSGQFUL, the SMSC queue is full. Usually the supplier’s side, and usually temporary. Persistent occurrences are worth raising.
Permission and account errors
0x00000045 ESME_RSUBMITFAIL, a general submit failure. Frustratingly vague; it often means the platform rejected the message for a reason it does not want to enumerate, such as a routing rule or a content filter. Ask the supplier for the underlying reason.
0x00000088 ESME_RINVOPTPARAMVAL, an optional parameter has a bad value. Check any TLVs you are setting.
Account balance and routing rejections are frequently returned as vendor-specific codes above 0x00000400, which is why the supplier’s error list matters as much as the specification.
Practical debugging order
- Confirm it is a submit rejection and not a delivery failure; they are different problems with different owners.
- If the code is above
0x00000400, go straight to the supplier’s documentation. - For addressing and content errors, reproduce with a single hand-built PDU before touching production code.
- Log the full
command_status, yourton/npi, the DCS, and the raw payload length for every rejection. Without those four fields a support ticket is guesswork. - If the code is generic, ask the supplier for the internal reason. Good platforms have one.
Connection details for both paths: SMPP v3.4 bind and HTTP REST API. Related reading: choosing between them.
Keep reading
Related insights
SMS Delivery Receipts and Fake DLRs
A delivery receipt is a claim, not proof. How DLRs are generated, what the status fields mean, and the patterns that show…
SMPP Throughput: Planning TPS and Binds
Why a bind rated at 100 TPS does not give you 100 messages per second, how the window size governs real throughput,…
SMPP vs HTTP API: Which Connection Should You Use for A2P SMS?
SMPP vs HTTP API: both reach the same routes. The choice is about session model, throughput and how your platform is built,…