A migration in trouble almost never presents as a data problem. It presents as a date. The cutover slips, then slips again, the vendor and the internal team each have a defensible account of why, and somebody senior asks whether more people would help.
More people will not help. In the stalled migrations I have been brought into, 80 to 90 percent of the actual problem was data, and the schedule was just the place the data problem became visible to management.
The tell is the spreadsheet
Before anyone declares a migration to be in trouble, there is a reliable early signal: people are hand-editing records in Excel to get them across.
That is the moment to intervene, and it usually goes unremarked because it looks like diligence. Somebody found a batch of records the tooling could not handle, so they fixed them by hand, and the migration moved forward. Everyone is relieved.
What it actually means is that the migration is no longer repeatable. A healthy migration is a tool run. You point it at the source, it runs, and you get a known result. You can run it again on Tuesday and get the same result. Every exception handled by a human in a spreadsheet is an outcome that exists exactly once, and cutover day is the day you find out how many of those there were.
The fix is not more careful spreadsheet work. It is to take each class of exception and build the cleanup into the pipeline, so the tool handles it. When the tool handles all of it, migration day stops being an event and becomes a scheduled job.
Run the migration before you move the date
The first thing I do on a rescue is run a full test migration into a scratch target, end to end, and see what comes out.
Not a sample. Not a discussion about what will probably break. Run it and measure it. That single exercise tells you where the pain points are, what the process actually is as opposed to what the plan says it is, and which failures are volume problems versus which are structural. Everything after that is informed.
That has to happen before anybody decides to move the cutover date. The date is downstream of the data, and renegotiating it first just buys another quarter to spend the same way you spent the last one.
It is almost always the data, in one of two shapes
The failures cluster into two kinds, and they need different fixes.
The inbound data is junk. One company had a skills field on its person records that had been free text for years, entered in whatever form each person happened to prefer. There is no mapping rule that turns that into structured skills in a target system, because the information was never structured in the first place. That has to be extracted and rebuilt, and it is a real project, not a migration step.
There is no place for the element. On another migration, source records carried up to three email addresses per person and the target system had exactly one field for it. That is not a data quality problem, it is a model mismatch, and there are only three honest answers: extend the target model, pick a rule and document what you are discarding, or park the extra data somewhere it can be recovered. What you cannot do is let the migration tool silently choose one, which is the default behavior and how firms lose a third of their contact information without noticing.
Neither of these is visible in a status report. Both of them show up on the first test run.
Write the tool that compares old to new
The single most useful thing I have built on a rescue was not part of the migration at all. It was a set of tools that compared the source data to the migrated data and showed me the gaps.
Most of my time went into those comparisons, and it was the right allocation. Once you can see, per record and per field, what made it across and what did not, post-migration cleanup stops being archaeology. You get a work list. You fix the pipeline for the classes that are systematic, you patch the new system for the ones that are not, and you can prove to the business that the data is whole.
Without that, the only detection mechanism you have is a user noticing that a record looks wrong, months later, and by then the source system may be gone.
Do not turn the old system off. Make it read-only.
This is the technique I would keep if I could keep only one.
On one cutover, we did not decommission the old platform. We kept a handful of licenses, set every remaining user to read-only, and monitored who logged in.
Three or four people kept going back. That was the whole signal, and it was worth more than any amount of user acceptance testing. Those users were not being difficult and they were not resisting change. They were going back because the new platform did not do something they needed, and each visit pointed directly at what. We fixed the gaps those visits identified. Usage of the old system fell to zero on its own, and nobody had to be told to stop.
Read-only is what makes it work. Nobody can enter new data into the old system, so you never end up with two live sources of truth. But the information about what you missed keeps arriving, and it arrives as behavior rather than as opinion.
Set an end date for it when you start. A few licenses for a few months is cheap insurance; an old platform that nobody ever gets around to decommissioning is a line item you will still be paying three years from now.
Sometimes the migration is not the problem
One caution, because it is the most expensive mistake I see on rescues: confirm that the platform being migrated to is the right answer before you spend six months getting there.
A company I worked with had followed its migration by buying a natural language search product to find records in the resulting system. Users could not find what they needed, and the search product took the blame. The search product was fine. It was being pointed at tens of thousands of records whose meaningful content sat unstructured in free-text fields, and no search tool can query that usefully.
Once the problem was named correctly, the fix took about two weeks. That story is worth understanding in full before you buy anything to sit on top of a migration, and it is the same lesson that shows up when a company reaches for AI where a good algorithm would do.
What a rescue actually looks like
Run the migration. Read the output. Categorize every failure as dirty data, model mismatch, or genuine tooling defect, because the three have different owners and different fix costs. Build the exception handling into the pipeline until a run is repeatable. Write the comparison tooling early, because you will use it for months. Cut over into a read-only old system and watch the logins.
Then set the date, when you can say what has to be true for it to hold. The migrations that go badly are not the ones with hard problems. They are the ones where the date was set first and the data was discovered afterward, and where nobody senior owned the whole estate well enough to say so out loud.