Published on
Most common cXML errors: understand, debug, fix
cXML errors are silent by design, poorly documented, and buyers rarely give details. This guide covers the Status codes you will actually hit in Magento 2 / Adobe Commerce integrations and how to debug them fast.
If you have ever searched how to debug a cXML message, you know the feeling: everything looks fine on the 200 OK side, but the cart never comes back, the buyer says it does not work, and your logs say nothing.
cXML errors are silent by design. The standard mixes HTTP codes and cXML Status codes, buyers (SAP Ariba, Coupa, Oracle Procurement, etc.) rarely return actionable messages, and each one has its own interpretation. This guide walks through the errors you will actually hit in production on Magento 2 and Adobe Commerce, with causes, examples, and how to resolve them.
Understanding cXML Status codes: the foundation of debugging
First thing to internalize: an HTTP 200 OK does NOT mean the message was accepted. cXML uses its own status layer via the <Status> element:
<cXML payloadID="..." timestamp="...">
<Response>
<Status code="200" text="OK">Success</Status>
</Response>
</cXML>
Typical structure:
- HTTP transport returns its own code (200, 401, 500…)
- The cXML message itself carries its own
<Status code="..." text="...">
In practice, a buyer can receive a HTTP 200 and find inside a <Status code="400"> rejecting the message. That is the first source of confusion in debugging: always look at the cXML <Status> before concluding everything is fine.
Authentication errors (4xx)
401 - Unauthorized
Most common cause: the SharedSecret you send does not match the one configured on the buyer side.
<!-- Sent to buyer -->
<Sender>
<Credential domain="NetworkId">
<Identity>supplier_id</Identity>
<SharedSecret>WrongSecret123</SharedSecret>
</Credential>
<UserAgent>Gatebold/1.0</UserAgent>
</Sender>
<!-- Buyer response -->
<Status code="401" text="Unauthorized">SharedSecret mismatch</Status>
Check first:
- Did the buyer rotate the secret without telling you? (Ariba does this regularly)
- Are you on sandbox or production? Secrets differ.
- Does the secret contain special characters that are mis-escaped in XML?
- Is there a UTF-8 BOM at the start of your file? (Breaks strict comparisons) (BOM: 3 invisible bytes
0xEF 0xBB 0xBFprepended to a UTF-8 file by some Windows editors like Notepad)
403 - Forbidden
The secret is correct, but the identity (<From> or <To>) does not match what the buyer has on file.
<From>
<Credential domain="NetworkId">
<Identity>AN01234567890</Identity>
</Credential>
</From>
On Ariba, this Identity is the ANID (Ariba Network ID). One character off = 403.
417 - Expectation Failed
The HTTP header is incomplete (typically Content-Type or Content-Length missing). A Magento 2 module misconfigured to send application/json instead of text/xml.
DTD schema errors (400 + 450)
400 - Bad Request (invalid schema)
The message does not respect the official cXML DTD grammar. The most common cases:
- Required element missing (
<BuyerCookie>absent inPunchOutSetupRequest) - Wrong child order (
<To>before<From>in<Header>) - Out-of-enum attribute value (
operation="update"instead ofcreate/inspect/edit) - Required attribute missing (
payloadIDortimestampon<cXML>)
450 - Bad/Missing data
cXML-specific: the message is syntactically valid but a business field is missing.
<!-- ItemIn without UnitPrice -->
<ItemIn quantity="2">
<ItemID>
<SupplierPartID>SKU-001</SupplierPartID>
</ItemID>
<ItemDetail>
<Description xml:lang="en">Ink cartridge</Description>
<!-- ❌ UnitPrice missing -->
</ItemDetail>
</ItemIn>
Buyer returns: <Status code="450" text="Bad/Missing data">UnitPrice required for ItemIn</Status>
Cart return errors (475)
475 is a proprietary code widely used for “processing error” (non-standardized business error).
<Status code="475" text="Processing error">
Item SKU-001 not found in buyer catalog
</Status>
Typical causes:
- Item sent that is not referenced in the buyer’s internal catalog (Ariba internal, Coupa CSP)
- Returned price differs from the negotiated contract price
- Unexpected currency (EUR sent while the contract is in USD)
- Missing or invalid UNSPSC code (see UNSPSC mapping)
Buyer-side errors
500 - Internal Server Error (on the buyer)
Not your problem, but you will still have to debug it. Often an e-proc-side crash with cryptic messages. Get the payloadID you sent and forward it to the buyer’s support.
Session timeout (no code, but cart lost)
The requisitioner takes too long on your store, their buyer-side session expires. No error is raised, but the PunchOutOrderMessage you send disappears into the void.
Lost SetupRequest (firewall / DNS)
The buyer says they sent the PunchOutSetupRequest, you see nothing in your logs. 9 times out of 10: your firewall blocks the buyer’s IP, or your DNS points to the wrong IP.
Fix: tail -f your Apache access logs while the buyer retries. If nothing arrives, the problem is upstream of your server.
Logs to enable for debugging cXML on Magento 2
This is probably the most useful section of this article. Without proper logs, you are debugging blind.
What you should systematically log:
- Full incoming XML payload (
PunchOutSetupRequest) with theSharedSecretredacted (****). - Outgoing XML payload (
PunchOutSetupResponseandPunchOutOrderMessage). - Precise timestamp (milliseconds) to reconstruct a timeline.
- Correlation ID: a UUID you generate on
SetupRequestreceipt, propagated everywhere, present in every log line. - HTTP Status + cXML Status on the buyer response (both!).
Where to store them in Magento 2:
var/log/punchout.logfor payloads (dedicated file, not insystem.log)- Daily rotation, 30-day retention (GDPR)
- Never the
SharedSecretcontent in clear, never the requisitioner’s personal details
Structured debug method
When a buyer reports an issue:
- Ask for the
payloadIDof the failing message (always present buyer-side) - Find the payload in your logs via this
payloadID - Validate the syntax with the cXML validator
- Check the Status in the response (HTTP + cXML)
- Cross-check buyer specs (Valid ANID? Catalog up to date? Contract prices?)
- If stuck: send the XML payload to buyer support with your
payloadIDand theircorrelationID
How Gatebold simplifies this debugging
On a custom Magento 2 integration, each error requires you to dig through several systems. The Gatebold platform centralizes:
- Structured logs per PunchOut session (auto correlation ID, timestamped payloads)
- Systematic DTD validation of messages before sending (preventive rejection)
- Error dashboard: Status code, frequency, buyer concerned
- Replay a message in debug mode without touching production
- SharedSecret rotation without redeploying Magento 2
For teams managing multiple buyers (Ariba, Coupa, Oracle, etc., at the same time), this level of observability is the difference between 2 hours of debug and 2 days.
Summary
The most frequent cXML errors you will hit:
| Code | Type | Typical cause | First reflex |
|---|---|---|---|
401 | Auth | SharedSecret mismatch | Check secret + environment |
403 | Auth | ANID/Identity mismatch | Compare with buyer config |
400 | Schema | Invalid DTD | Validate via our validator |
450 | Business | Required data missing | Check outgoing payload |
475 | Buyer | Catalog/price/currency | Trace the PunchOutOrderMessage |
500 | Server | Buyer crash | Get payloadID + escalate to support |
General rule: log everything, redact secrets, keep 30 days. Without that, every production error takes 5x longer to resolve.
For the complete list of cXML Status codes with causes, debug and fix, see our cXML error codes reference - sourced from the cXML Reference Guide 1.2.070 with a bonus 15 common non-code pitfalls (encoding, payloadID, SharedSecret, etc.).
For technical articles on buyer-specific implementations, see our guides for SAP Ariba, Coupa, Oracle Procurement, etc. If you want to discuss it for your Magento 2 project, contact us.
Frequently asked questions
How do I debug a cXML 401 Unauthorized error?
How do I see the cXML payloads sent to a buyer?
var/log/punchout.log) that captures the PunchOutSetupRequest, PunchOutSetupResponse and PunchOutOrderMessage with a correlation ID (UUID) propagated across the whole PunchOut session. Without those logs, debugging is blind. Always redact the SharedSecret.