> How to build an agent for ERP integration error handling: an error taxonomy from IDoc and OData contracts, allowlisted runbooks, safe retries and dedup.
>
> Web page: https://balazscsorba.com/blog/erp-integration-error-agent · Language: English · Also available in: [Deutsch](https://balazscsorba.com/de/blog/erp-integration-error-agent.md) · [Magyar](https://balazscsorba.com/hu/blog/erp-integration-error-agent.md)
> Author: Balázs Csorba · Published: 2026-10-09 · Keywords: ERP integration error handling, IDoc status 51, SAP OData error handling, dead letter queue integration, integration retry idempotency, order sync failed shop ERP, AI agent triage logs, SAP Integration Suite JMS retry, integration error taxonomy, incident deduplication

[Blog](https://balazscsorba.com/blog)/AI agents

# An agent that triages ERP integration errors: taxonomy, runbooks and safe retries

How to build an agent for ERP integration error handling: an error taxonomy from IDoc and OData contracts, allowlisted runbooks, safe retries and dedup.

[Balázs Csorba](https://balazscsorba.com/about)·October 9, 2026·8 min read

-   ERP integration
-   SAP
-   Error handling
-   Retries
-   AI agents

![A pipe with a warning at one joint, cards sorted into a tray below.](https://balazscsorba.com/images/blog/erp-integration-error-agent/cover.webp?v=9ef6cd8855)

## Key takeaways

-   Most shop, PIM and ERP integration failures fall into five families: mapping and validation, missing master data, price or customer blocks, availability conflicts, and infrastructure errors.
-   Build the error taxonomy from real contracts such as IDoc status records and OData error objects, and fingerprint errors so the same class always maps to the same runbook.
-   Classify rules-first and use the LLM only for unstructured runtime text; the agent acts only through allowlisted, audit-logged runbook actions.
-   Retry only idempotent operations with bounded attempts and exponential backoff with jitter; data and validation errors go to quarantine and a ticket for the owning team.
-   MuleSoft’s 2026 benchmark reports that IT teams spend 36% of their time on custom integration work, so measure failed messages per interface, time to resolve and the share resolved without a person.

On this page

1.  [What breaks between shop, PIM and ERP?](https://balazscsorba.com/#what-breaks-between-shop-pim-and-erp)
2.  [How do you build an integration error taxonomy?](https://balazscsorba.com/#taxonomy-from-error-contracts)
3.  [How does the agent’s triage loop work?](https://balazscsorba.com/#the-agent-triage-loop)
4.  [When is a retry safe, and what goes in a runbook?](https://balazscsorba.com/#safe-retries-and-runbooks)
5.  [Which queue and dead-letter mechanics should you know?](https://balazscsorba.com/#queue-and-dlq-mechanics)
6.  [Which guardrails does a triage agent need?](https://balazscsorba.com/#guardrails-and-audit)
7.  [What is an integration triage agent worth?](https://balazscsorba.com/#what-it-is-worth)
8.  [When should you not build an agent for this?](https://balazscsorba.com/#when-not-to-build-an-agent)
9.  [A one-page implementation checklist](https://balazscsorba.com/#implementation-checklist)
10.  [Sources](https://balazscsorba.com/#sources)

Listen to this article

0:000:00

**ERP integration error handling** is the operational side of connecting a shop, a PIM and an ERP: reading failed messages, deciding whether to retry or fix, finding whose system owns the fix, and knowing which orders are affected. An agent can take most of the reading and sorting off the integration team, as long as it classifies against a real error taxonomy, acts only through a short list of safe runbook actions, and leaves every change to business data with people.

This article covers what breaks between shop, PIM and ERP, a taxonomy built from SAP’s error contracts, the agent’s triage loop, safe retries and runbooks, queue and dead-letter mechanics, guardrails, the business case and when a rules engine is the better answer. The design of the sync itself is in [the Pimcore ERP delta sync](https://balazscsorba.com/blog/pimcore-erp-delta-sync).

## What breaks between shop, PIM and ERP?

Five failure families cover most incidents: mapping and validation errors, missing or blocked master data, price and customer status blocks, availability and allocation conflicts, and authentication, timeout and infrastructure errors. Every triage answers three questions: retry or fix, whose system owns the fix, and how many orders are affected.

The distinction between retry and fix matters most. Only the last family improves with time; a missing material or a blocked customer fails the same way on every retry, and an integration that retries those forever turns one data problem into hundreds of noisy alerts. Working on B2B commerce systems with Spryker and Pimcore, I have found that the part teams keep after a project is not the integration code but the runbook library and the error dashboard, so design for those from the start.

## How do you build an integration error taxonomy?

Build it from the error contracts your systems already emit, not from labels you invent. SAP gives you two good ones: IDoc status records and OData error objects.

-   **IDoc status records.** Per SAP’s status list, cross-checked in [SAP Community](https://community.sap.com/t5/technology-q-a/idoc-status-codes/qaq-p/3961848), 51 means “Application document not posted”, 53 “Application document posted”, 64 “IDoc ready to be transferred to application”, 66 “IDoc is waiting for predecessor IDoc” and 68 “Error, no further processing”. SAP’s ALE documentation says inbound processing of a failing IDoc is terminated, a workflow item is raised, and after correction the IDoc is resubmitted; report RBDMANI2 resubmits status 51 and 63 IDocs and can be scheduled to collect those that failed on a lock ([SAP Library](https://help.sap.com/saphelp_aii710/helpdata/en/0b/2a6743507d11d18ee90000e8366fc2/content.htm)).
-   **OData error objects.** An OData V4 error response is a JSON `error` object with a language-independent `code`, a message, an optional `target` pointing at the offending property, and a `details` array. SAP CAP adds a numeric severity, and draws a clear line: throwing a `ServiceException` aborts and rolls back, while messages added through the Messages API do not stop processing ([SAP CAP](https://cap.cloud.sap/docs/java/event-handlers/indicating-errors)). A warning with a target is a report, not a retry candidate.

Error class

Detection signal

Retryable?

Safe first action

Fixing owner

Mapping, validation

IDoc 51 with field message; OData error with target

no

quarantine, ticket with field

integration team

Missing master data

IDoc 51, “material not found”

no

quarantine, ticket

master data team

Customer or price block

application message on posting

no

notify order desk

sales, finance

Availability, allocation

ATP or allocation message

sometimes

notify, retry after replenishment

supply chain

Lock, timeout, 5xx

IDoc 51 on lock; HTTP 5xx; queue retry

yes, if idempotent

bounded retry

platform team

## How does the agent’s triage loop work?

Normalize every signal into one record, classify with rules first, decide from the taxonomy, act within an allowlist, record what happened, and deduplicate by fingerprint. The LLM is one component of the classifier, used only for unstructured runtime text that no rule matches.

![Integration error triage loop Six stages from left to right: signals from IDoc status records, Cloud Integration logs, queues and dead-letter queues, OData error responses and the shop’s sync queue; a normalizer that turns them into one record shape; a classifier that applies rules first and uses an LLM only for unstructured runtime text; a decision from the taxonomy; an allowlisted action such as retry, quarantine, notify or ticket; and a dedup store that counts fingerprints and links known incidents, feeding runbook and mapping fixes back.](https://balazscsorba.com/images/blog/erp-integration-error-agent/diagram-11.webp?v=a7a06bd6a5)

The triage loop: every signal becomes one record shape, rules decide first, and the agent can only take actions from a short allowlist.

```
// One record shape for every signal (sketch)
type IntegrationError = {
  source: 'idoc' | 'cpi' | 'odata' | 'queue' | 'shop'
  interface: string      // e.g. "ORDERS inbound", "stock sync"
  entityKey: string      // order number, material, customer
  code: string           // IDoc status + message class/number, OData error code, DLQ reason
  target?: string        // OData target path or IDoc segment/field
  text: string           // runtime message text: untrusted input for any LLM step
  retryCount: number
}

// Same class, same runbook: fingerprint without volatile values
const fingerprint = (e: IntegrationError) =>
  sha256([e.source, e.interface, e.code, e.target ?? '', stripVolatile(e.text)].join('|'))
// stripVolatile removes ids, numbers and timestamps, so
// "material 4711 not found" and "material 4712 not found" share one fingerprint
```

The fingerprint is what turns a flood into a list. Two hundred failed order IDocs with the same missing material become one incident with a count and a list of affected orders, linked to one ticket. Treat the runtime text as untrusted input: it can contain customer-supplied strings, so the LLM step only classifies and summarizes, and never decides an action outside the taxonomy. My own `jev-decide` skill has the same shape, a typed decision with a confidence where low confidence goes to a human, and the triage classifier should return exactly that: error class, retryable, owner, confidence.

## When is a retry safe, and what goes in a runbook?

A retry is safe when the error is transient and the operation is idempotent, and it stays safe only when attempts are bounded and spread out. Everything else is quarantine plus a ticket. A runbook is a short list of named actions per error class: auto-retry, quarantine and assign an owner, notify, open a ticket with context, or propose a mapping change.

![Retry decision tree for integration errors A failed message branches into four classes. Transient errors such as timeouts, 5xx responses and locks get a bounded retry with backoff and jitter, for idempotent operations only. Data and validation errors such as a missing material go to quarantine with a ticket for the owning team. Business-rule errors such as a credit block notify the order desk with context. Unknown errors from free-text messages are classified by an LLM, and low-confidence results go to a human.](https://balazscsorba.com/images/blog/erp-integration-error-agent/diagram-16.webp?v=9e933cc86f)

The retry decision tree: only transient errors on idempotent operations are retried; data and business errors go to the people who own the fix, and unknown errors are classified with a confidence threshold.

Idempotency is a receiver-side contract. Stripe’s API is the clean reference: an idempotency key lets a caller repeat a request without performing the operation twice, and reusing a key with different parameters returns an error ([Stripe](https://docs.stripe.com/api/idempotent_requests)). Any call that creates a sales order, delivery or invoice needs the same contract before an agent may retry it; the duplicate sales order is the failure that costs real money, which is why [email order entry automation](https://balazscsorba.com/blog/b2b-email-order-entry-llm) puts the key on the create call. Backoff alone is not enough either: in AWS’s simulation of 100 contending clients, adding full jitter to capped exponential backoff cut the call count by more than half ([AWS](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)).

```
// Capped exponential backoff with full jitter, for idempotent operations only
function retryDelayMs(attempt: number, baseMs = 1_000, capMs = 60_000): number {
  const ceiling = Math.min(capMs, baseMs * 2 ** attempt)
  return Math.random() * ceiling
}

const MAX_ATTEMPTS = 5   // bounded: after that, quarantine and open a ticket
```

The runbook library is also the feedback loop. When the same fingerprint keeps landing in quarantine, the agent proposes a mapping fix as a ticket to the data owner, with the count, the affected orders and the example payload. That is how recurring classes disappear instead of being handled forever. Retrying LLM API calls follows similar rules but a different failure mode, covered in [LLM rate limits, retries and provider fallback](https://balazscsorba.com/blog/llm-rate-limits-retries-provider-fallback).

## Which queue and dead-letter mechanics should you know?

Know exactly what lands in each dead-letter queue, because the rules differ per platform and an agent that assumes the wrong one misses failures. Three examples cover most stacks.

-   **SAP Cloud Integration JMS queues:** for non-exclusive JMS queues, as documented by SAP in 2017, the retry interval defaults to one minute, exponential backoff doubles it after each failure, and a maximum interval of 60 minutes or more is recommended ([SAP Community](https://community.sap.com/t5/integration-blog-posts/cloud-integration-configure-asynchronous-messaging-with-retry-using-jms/ba-p/13315669)). The dead-letter queue there is narrow: it holds messages that could not be processed because a node crashed, retried twice and then parked for manual action; messages that fail because of a processing error do not go there ([SAP Community](https://community.sap.com/t5/technology-blogs-by-sap/cloud-integration-configure-dead-letter-handling-in-jms-adapter/ba-p/13325734)). Newer exclusive queues behave differently, so check which kind an interface uses.
-   **Amazon SQS:** a redrive policy with `maxReceiveCount` moves messages to a dead-letter queue, whose expiry is based on the original enqueue time, so its retention must be longer than the source queue’s ([AWS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)).
-   **Azure Service Bus:** dead-lettered messages carry `DeadLetterReason` and `DeadLetterDescription`, for example `MaxDeliveryCountExceeded` after the default of 10 deliveries, and Microsoft recommends putting the exception type and stack trace into those fields ([Microsoft Learn](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dead-letter-queues)). That is free input for the classifier.

Durable execution engines encode the same rules as defaults. Temporal retries activities with exponential backoff, a coefficient of 2.0 from a one-second initial interval up to 100 seconds, treats a maximum of zero attempts as unlimited, and its documentation names bad input data as the reasonable case for a non-retryable error ([Temporal](https://docs.temporal.io/encyclopedia/retry-policies)). If you run order workflows on it, the agent reads its failures like any other signal; the platform itself is reviewed in [Temporal](https://balazscsorba.com/blog/temporal).

## Which guardrails does a triage agent need?

Read-only by default, actions from an allowlist only, a dry-run mode, approval gates per action class, and a full audit trail. OWASP’s Top 10 for LLM applications lists excessive agency, giving an LLM-driven system more functionality, permissions or autonomy than its task needs, as LLM06 in its 2025 edition ([OWASP GenAI](https://genai.owasp.org/llmrisk/llm062025-excessive-agency/)).

**“Fix the customer record” is never an agent action**

The agent may retry an idempotent call, quarantine a message, notify someone or open a ticket with context. It may not change master data, mappings or order contents, even when it is confident about the fix. Those changes go to the owning team as a proposal. The patterns for that handoff are in [human-in-the-loop AI agents](https://balazscsorba.com/blog/human-in-the-loop-ai-agents).

A good ticket is half the value. It carries the interface, the IDoc number or message ID, the message class and number, the entity key, the fingerprint count, the affected orders and a link to the runbook. I open tickets like that every day through a Jira MCP server with 20 tools, and the difference between a ticket with context and one without is measured in analyst minutes.

## What is an integration triage agent worth?

It is worth the integration time it frees and the failed orders it surfaces before customers notice. No published figure exists for analyst hours saved by triage automation or for the cost of a failed B2B order, so the business case rests on context numbers and your own baseline.

-   **Integration load:** MuleSoft’s 2026 Connectivity Benchmark, a survey of 1,050 IT leaders from October to November 2025, reports that IT teams spend 36% of their time designing, building and testing custom integrations, that the average organization runs 957 applications with 27% connected, and that 26% of IT projects missed their deadline ([MuleSoft](https://blogs.mulesoft.com/agentic-perspectives/connectivity-benchmark-report/)).
-   **Order errors drive churn:** in a Sana Commerce study of 750 B2B buyers from September 2024, 33% reported order errors caused by inaccurate web-store data and 75% would consider switching suppliers for a better experience ([Procurement Magazine](https://procurementmag.com/procurement-strategy/sana-real-time-data-key-to-persuading-b2b-buyers); vendor survey).

For a head of e-commerce operations or an ERP integration lead, baseline four numbers before the pilot: failed messages per interface per week, time to resolve per error class, the share resolved without a person, and manual touches per failed order. Then count the recurring classes that disappear through mapping fixes; that number is the one a COO understands.

## When should you not build an agent for this?

Do not build one when message volume is low, when every signal is already structured, when there is no observability to read from, or when the real problem is an unresolved design flaw upstream. In those cases a rules engine plus alerting wins, and an LLM adds cost and a new failure mode without adding signal.

## A one-page implementation checklist

1.  Pick one interface and one error class for the pilot, such as inbound order IDocs.
2.  Write the taxonomy from real status codes and error objects, with an owner per class.
3.  Normalize all signals into one record shape and fingerprint without volatile values.
4.  Classify rules-first; send only unmatched free text to the LLM, with a confidence threshold.
5.  Allowlist the actions, start in dry-run mode, and require approval per action class.
6.  Retry only idempotent calls, bounded, with backoff and jitter.
7.  Log every decision and action with the fingerprint, the rule or model version and the outcome.
8.  Baseline the four metrics and review recurring classes monthly with the data owners.

A fixed-scope triage pilot on one interface, with a written taxonomy, a runbook library, dedup reporting and a before-and-after from your own logs, is a well-defined project. If you want help scoping one, see my [B2B e-commerce work](https://balazscsorba.com/expertise/b2b-ecommerce-developer).

## Sources

1.  [SAP Library: IDoc interface and ALE exception handling](https://help.sap.com/saphelp_aii710/helpdata/en/0b/2a6743507d11d18ee90000e8366fc2/content.htm)
2.  [SAP Community: IDoc status codes](https://community.sap.com/t5/technology-q-a/idoc-status-codes/qaq-p/3961848)
3.  [SAP CAP: indicating errors (Java)](https://cap.cloud.sap/docs/java/event-handlers/indicating-errors)
4.  [SAP Community: Cloud Integration asynchronous messaging with retry using JMS (2017)](https://community.sap.com/t5/integration-blog-posts/cloud-integration-configure-asynchronous-messaging-with-retry-using-jms/ba-p/13315669)
5.  [SAP Community: Cloud Integration dead-letter handling in the JMS adapter (2017)](https://community.sap.com/t5/technology-blogs-by-sap/cloud-integration-configure-dead-letter-handling-in-jms-adapter/ba-p/13325734)
6.  [Temporal: retry policies](https://docs.temporal.io/encyclopedia/retry-policies)
7.  [Amazon SQS: dead-letter queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)
8.  [Azure Service Bus: dead-letter queues](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dead-letter-queues)
9.  [Stripe API reference: idempotent requests](https://docs.stripe.com/api/idempotent_requests)
10.  [AWS Architecture Blog: Exponential backoff and jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)
11.  [MuleSoft: 2026 Connectivity Benchmark Report](https://blogs.mulesoft.com/agentic-perspectives/connectivity-benchmark-report/)
12.  [OWASP GenAI Security Project: LLM06:2025 Excessive Agency](https://genai.owasp.org/llmrisk/llm062025-excessive-agency/)

## Frequently asked questions

What does IDoc status 51 mean?

Per SAP’s IDoc status list, status 51 means “Application document not posted”: the IDoc reached the application but posting failed, for example because of missing master data, a validation error or a lock. Inbound processing of that IDoc stops; after the cause is fixed it can be resubmitted, for example with report RBDMANI2, which SAP also suggests scheduling for lock problems.

Which ERP integration errors are safe to retry automatically?

Transient infrastructure errors such as timeouts, 5xx responses and locks, and only when the operation is idempotent, with bounded attempts and backoff with jitter. Data and validation errors, such as a missing material or a blocked customer, do not improve with retries; they belong in quarantine with a ticket to the team that owns the data.

Can an AI agent fix ERP integration errors on its own?

It should not change business data. A useful agent reads signals, classifies errors, deduplicates incidents and executes a short allowlist of safe actions such as a bounded retry or opening a ticket with full context. Fixing a customer record or a mapping is a human change, proposed by the agent and approved by the data owner.

What is a dead letter queue in SAP Cloud Integration?

In Cloud Integration’s non-exclusive JMS queues, as documented in 2017, the dead-letter queue holds messages that could not be processed because a worker node crashed: they are retried twice and then parked for manual action. Messages that fail because of a processing error do not go there, so they need their own monitoring.

How do you measure an integration triage agent?

Baseline before the pilot and compare after: failed messages per interface per week, time to resolve per error class, the share resolved without a human, manual touches per failed order, and recurring classes eliminated through mapping fixes. No published benchmark exists for these, so your own logs are the evidence.

Written by Balázs Csorba

Senior fullstack & AI engineer in Styria, Austria – 10+ years of Vue, Nuxt, Node.js and PHP, now building tooling for AI agents.

[B2B e-commerce & PIM →](https://balazscsorba.com/expertise/b2b-ecommerce-developer)[About me →](https://balazscsorba.com/about)

## More articles

-   [Designing tools for AI agents: names, descriptions, schemas and error messages](https://balazscsorba.com/blog/agent-tool-design-descriptions-errors)
-   [Migrating a legacy codebase with coding agents: a strangler fig playbook](https://balazscsorba.com/blog/coding-agents-legacy-codebase-migration)
-   [Background coding agents that open PRs: a practical async workflow](https://balazscsorba.com/blog/background-agents-async-pr-workflow)
-   [Context rot in long-running agents: clearing, compaction, memory and sub-agents](https://balazscsorba.com/blog/context-rot-compaction-long-running-agents)

## Sounds like what you need?

Tell me about your project or role – I’d love to hear from you.

[Get in touch](mailto:contact@balazscsorba.com) [Connect on LinkedIn](https://www.linkedin.com/in/balazs-csorba)
