Skip to content
Gatebold

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:

  1. Did the buyer rotate the secret without telling you? (Ariba does this regularly)
  2. Are you on sandbox or production? Secrets differ.
  3. Does the secret contain special characters that are mis-escaped in XML?
  4. Is there a UTF-8 BOM at the start of your file? (Breaks strict comparisons) (BOM: 3 invisible bytes 0xEF 0xBB 0xBF prepended 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 in PunchOutSetupRequest)
  • Wrong child order (<To> before <From> in <Header>)
  • Out-of-enum attribute value (operation="update" instead of create/inspect/edit)
  • Required attribute missing (payloadID or timestamp on <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:

  1. Full incoming XML payload (PunchOutSetupRequest) with the SharedSecret redacted (****).
  2. Outgoing XML payload (PunchOutSetupResponse and PunchOutOrderMessage).
  3. Precise timestamp (milliseconds) to reconstruct a timeline.
  4. Correlation ID: a UUID you generate on SetupRequest receipt, propagated everywhere, present in every log line.
  5. HTTP Status + cXML Status on the buyer response (both!).

Where to store them in Magento 2:

  • var/log/punchout.log for payloads (dedicated file, not in system.log)
  • Daily rotation, 30-day retention (GDPR)
  • Never the SharedSecret content in clear, never the requisitioner’s personal details

Structured debug method

When a buyer reports an issue:

  1. Ask for the payloadID of the failing message (always present buyer-side)
  2. Find the payload in your logs via this payloadID
  3. Validate the syntax with the cXML validator
  4. Check the Status in the response (HTTP + cXML)
  5. Cross-check buyer specs (Valid ANID? Catalog up to date? Contract prices?)
  6. If stuck: send the XML payload to buyer support with your payloadID and their correlationID

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:

CodeTypeTypical causeFirst reflex
401AuthSharedSecret mismatchCheck secret + environment
403AuthANID/Identity mismatchCompare with buyer config
400SchemaInvalid DTDValidate via our validator
450BusinessRequired data missingCheck outgoing payload
475BuyerCatalog/price/currencyTrace the PunchOutOrderMessage
500ServerBuyer crashGet 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?
First, check the SharedSecret on the buyer side (often rotated silently), compare sandbox vs production environments (the secrets differ), and verify no UTF-8 BOM was added at the start of the file. Enabling dedicated Magento 2 logs (with the SharedSecret redacted) lets you quickly compare the supplier-side configuration against the buyer-side one.
How do I see the cXML payloads sent to a buyer?
Enable a dedicated log on Magento 2 (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.
What does a cXML Status code 450 mean?
450 is a cXML-specific code that means Bad/Missing data: the message is syntactically valid but a required business field is missing (UnitPrice, currency, unit of measure, etc.). Do not confuse it with 400 which flags a DTD schema violation.
Why does a PunchOutOrderMessage get lost at the buyer?
Three typical causes: buyer-side session expired while the requisitioner lingered on the Magento 2 storefront, item not referenced in the buyer's internal catalog (often triggers Status 475), or price/currency drift from the negotiated contract. The payloadID in the logs lets you locate the session on the buyer side.
How do I debug a cXML cart return that never comes back?
Check in order: (1) is the payloadID visible in your Magento 2 logs? (2) the Status code in the buyer response (HTTP and cXML - both can differ), (3) is the buyer session still active, (4) is the supplier-side firewall/DNS letting the incoming request through. Without a payloadID, escalating to buyer support is useless.
Which logs should I enable to debug cXML on Magento 2?
At minimum: full incoming XML payload (SharedSecret redacted), outgoing XML payload, precise timestamp (ms), correlation ID (UUID) propagated across the session, HTTP Status and cXML Status of the buyer response. Daily log rotation, 30-day retention to stay GDPR-compliant (payloads contain personal data about the requisitioner).