Bad data is always discovered during the load

In 24% of the 41 stalled implementations we have been called into, the primary cause was data that turned out to be worse than anyone knew — and it was almost always found during the load rather than during the diagnostic. The timing is the problem, not the data.

By The erp.io team — Research and engineering

Across the 41 stalled implementations we have been called into, data that turned out to be worse than anyone knew was the primary cause in 24% of them. That sample skews toward severe failures — people call us when a project is already in trouble, not when it is merely uncomfortable — and the full method is on the failure-modes page. The number is not the interesting part anyway. The timing is.

In almost every one of those cases the problem was found during the load. Not during selection, not during the diagnostic, not during design. During the load, which is to say after the contract was signed, after the design was agreed, and after a go-live date had been communicated to people who would be annoyed by it moving.

Why it surfaces so late

Looking properly at your own data is unglamorous, unbudgeted and mildly humiliating, and no phase of a typical implementation forces anyone to do it. The diagnostic looks at process. The design looks at the target state. Both are conversations about how things ought to work, and neither requires anybody to open the customer master and count how many rows have a country code that is not a country.

The load is the first activity that cannot proceed on assumptions. It reads every row. It is also, by design, the last activity before go-live, which means the first honest look at the data happens at the exact moment there is no schedule left to absorb what it finds.

Every implementation plan contains a step where the data is finally examined. In most plans that step is called "cutover".

What actually gets found

Rarely anything exotic. The recurring set, in rough order of how often we see it:

  • Duplicate parties that were never duplicates in the old system, because the old system let two records share a name and the new one enforces a key. Merging them is a business decision about which history is real, not a technical one, and it needs someone who can make it.
  • Balances that tie in aggregate and not in detail. The trial balance is fine. The sub-ledger supporting it contains entries nobody can attribute. This is the one that turns a two-week load into a two-month one.
  • Fields used for something other than their name. A memo field carrying routing instructions, a customer reference holding a project code. Every one of these is a rule that exists only in somebody’s head and has to be discovered by asking.
  • History that was migrated once already and carries the scars of that migration — truncated descriptions, dates defaulted to the migration date, a currency column that means two different things either side of a cutover in 2019.

The fix is a destructive dry load, early

The intervention is not better tooling and it is not a longer cleansing phase. It is moving the discovery forward, and the only reliable way to do that is to load everything into a throwaway environment before the design is agreed — not a sample, not the master data, everything, including the transactional history nobody intends to bring across.

It will fail. That is the point. The failures are a list, the list is the real scope, and having it in week three rather than week twenty-six is the entire value of the exercise. The environment is then deleted, which is what makes it safe to be careless in.

Three things make it worth doing properly rather than as a formality:

  • Load the history, even the history you plan to leave behind. The decision to leave it behind is usually revisited once someone from finance discovers what "we will keep it in the old system" means in practice for an audit.
  • Count the rows that fail, and keep the count. A cleansing effort with no baseline cannot be shown to have worked, and "the data is much better now" is not a statement anyone should accept before a cutover.
  • Give every failure class an owner with a name. The duplicate-customer question is not a data question and cannot be closed by whoever is running the load.

What this costs us to say

A destructive dry load adds two to four weeks to the front of an engagement and produces nothing a buyer can look at. It is the least attractive thing we propose, it makes our timelines longer than the ones we are quoted against, and we have lost work over it.

We propose it anyway, because the alternative is not a faster project. It is the same discovery at a worse moment, which is what the 24% is a record of.

If you are earlier than that — still choosing — the diagnostic questions we ask are in the requirements guide, and what implementations actually cost, from 63 quotes we were shown, is in the pricing study.

The erp.io team

We publish under one byline because no individual owns a finding here. Who you actually work with is on the team page, including the parts of a small team that are a disadvantage.

Keep reading

Other posts.

Closing faster is mostly a reconciliation problem

Teams trying to shorten the close usually attack the last three days. The time is almost never there. It is in the accounts that are only reconciled once a month, and the reason that is hard is not effort.

26 August 2026 · Read →

The reference call question that cannot be rehearsed

Vendor-supplied references are selected, prepared and generally honest, which is what makes them nearly useless. Four questions that produce information anyway, and one that does not work.

19 August 2026 · Read →

What an agent structurally cannot do inside a ledger

Our agents run at 94% accuracy on the workflow they are best at and 66% on the one they are worst at, measured across 23 customers. The gap is not a training problem. It is a description of which tasks have a checkable answer and which do not.

12 August 2026 · Read →

Everything else we publish.

Primary research with stated sample sizes, buyer guides, and comparisons scored on published weights.