Google Drive to SharePoint migration — what could go wrong and how we handle it
A cross-cloud migration is a long-running operation against two APIs you don't control, both of which rate-limit aggressively. This page walks through what MigrationFox checks before it starts, what it retries silently, what it skips on purpose, and what you should actually watch for on the live dashboard.
Example mid-run dashboard for a ~40K file Google Drive migration. Retries column showing a non-zero number is normal and healthy.
WHAT YOU'LL SEE
A healthy run is defined by Failed = 0, not Retries = 0. Retries climbing into the hundreds while Failed stays at zero means the retry logic is doing its job — the destination API throttled us and we backed off. Only panic when the Failed counter starts ticking.
Pre-flight checks (before a single byte moves)
When you click Start migration, MigrationFox runs a silent pre-flight pass against both endpoints. You see it as the few seconds between clicking and the progress bar appearing. If any of these fail, the job never enters the transfer phase — no partial state to clean up.
- Source credential. A test call against
files.list?pageSize=1on the Google Drive API. Confirms the service account or OAuth token is still valid and scoped fordrive.readonlyor higher. Expired service account keys surface here, not an hour into the run. - Source scope. The scanned domain / shared drive / user is resolvable. A common failure mode: service account delegation was authorized for only one admin's domain and you're scanning a second domain that was added later.
- Destination credential. A
GETagainst the destination site collection. Confirms the Azure AD app registration's app-only token can still authenticate and that the site URL didn't change since credentials were saved. - Destination write permission. A tiny
PUTof a zero-byte probe file into_mfox_probe/, followed by aDELETE. The probe file is never visible to end users — if you see leftover probe files in SharePoint, a previous job was force-killed mid-preflight; delete them manually. - Tenant blocked-file-type policy. We read
Get-SPOTenant DisallowedFileTypesequivalent from the tenant and cache it for the run. This is how we know to mark.exe/.dllas pre-skip instead of failing at upload time. See the executable handling doc for how that list is enforced.
What fails at 99% and how MigrationFox retries
The biggest cause of "my migration stalled" support tickets isn't credentials or disk space — it's transient 429s, 5xxs, and socket timeouts that would look like failures if we didn't retry them. The retry ladder:
| Symptom | What happens | When you'd see it |
|---|---|---|
429 Too Many Requests (either side) | Exponential backoff, starting at 2s, doubling up to 60s, capped at 8 attempts per file. Retry count increments, file is re-queued. | Very common on large jobs — Google Drive and SharePoint both rate-limit per-user and per-tenant. |
500 / 502 / 503 / 504 | Retried up to 5 times with jittered backoff. Treated as transient infrastructure noise. | Expected a few dozen times on any multi-GB job. |
| Socket timeout / connection reset | Retried up to 5 times. On the 6th, the worker reconnects with a fresh HTTP/2 session (old one was probably half-closed by a load balancer). | More common on long jobs — load balancers idle-timeout connections after ~30 minutes. |
| Checksum mismatch after upload | Destination file is deleted and the source is re-uploaded, up to 3 attempts. On the 4th, the file is marked Failed (not Skipped) and logged with both checksums. | Rare but happens — usually a partial network-level corruption. |
| Token expiry mid-run | Token refresh triggers automatically; in-flight requests complete with the old token and new ones use the refreshed token. | Invisible on the dashboard unless the refresh itself fails, which surfaces as a pause-and-prompt. |
401 Unauthorized (persistent) | Job pauses, not fails. You get a notification to re-authenticate; the job resumes exactly where it left off. | Password rotation or admin consent revocation mid-run. |
TIP
The Retries column climbing into the thousands on a huge job is not a problem; it is how the backoff ladder protects the run from source-side throttles. The numbers to watch are Failed and Skipped (unexpected). Both should be near zero by end of job.
File types that skip automatically
Two categories of file never get a real upload attempt. Both are counted under Skipped on the dashboard, broken out on the final report.
- OS / app artifacts.
.DS_Store,Thumbs.db,desktop.ini,~$*, Trash folders, and similar noise — the full pattern list lives in the auto-skip reference. On a typical Google Drive source these are 3–10% of file count and essentially zero bytes. - Executables and other destination-blocked types. Any extension on the destination tenant's
DisallowedFileTypeslist is skipped at the source pre-read step, not at upload. See the executable handling doc for how to relax the list if you actually need installers in SharePoint.
Google-native files (Docs, Sheets, Slides, Forms) are not skipped — they're exported to Office formats (.docx, .xlsx, .pptx) and uploaded normally. Google Drawings and Google Sites pages are exported to PDF. Google Forms and Jamboards are metadata-only (destinations don't have an equivalent) and surface as warnings on the final report.
How to check progress
Three views, all live:
- Job Detail page. The dashboard shown above — full counters, log tail, retry breakdown. Polls every 10 seconds.
- Client Live View. A share URL that shows the same progress bar + phase strip without credential names or source paths. Send this to the client instead of screenshots. See client live view.
- Webhooks.
job.started,job.progress(every 5%),job.completed,job.failed. Wire into Slack or a PSA for overnight unattended runs.
Common reasons a migration slows
Throughput drops from 4 MB/s to sub-1 MB/s mid-run
Almost always source-side throttle. Google Drive enforces a per-user and a per-project quota; the per-project quota resets every 100 seconds. If the scan hit a burst of heavy files, the first few hundred seconds look fast, then throttle kicks in. The backoff ladder smooths this out — throughput settles into whatever the steady-state quota allows, which is often around 2–4 MB/s for a single service account.
Long idle-looking gaps in the log strip
Worker is waiting on a single giant file. One 8 GB video upload at 3 MB/s is a 45-minute block during which no other activity shows. The other 15 workers are still busy — check the Workers tile to confirm.
SharePoint destination suddenly 503s for minutes
Microsoft 365 is doing a regional failover or applying a patch. The backoff ladder handles it; you'll see Retries spike, then recover. No action needed unless it persists more than ~15 minutes, at which point the job auto-pauses and notifies you.
When to split into multiple jobs
A single Google Drive source scales cleanly up to about 500 GB / 500K files per job. Beyond that, splitting into multiple parallel jobs is almost always faster and always easier to recover from.
- By shared drive. One job per shared drive is the cleanest split — scope boundaries match API permission boundaries.
- By top-level folder. For a single mega-drive, split at the first folder layer. MigrationFox respects these splits and each job gets its own independent retry ladder.
- By wave. For weekend cutovers, split the inactive/archival content into a weekday job that runs at 25% bandwidth, then run the active content in a 2-hour window on Saturday night.
Each job runs on its own worker pool with its own rate-limit budget, so two 250 GB jobs in parallel finish faster than one 500 GB job. The practical cap is around 4 parallel jobs per tenant before the destination-side throttle becomes the bottleneck.
DON'T
Never stop-and-restart a job because the throughput looks "too slow." Restarts waste the built-up backoff context and force the job to re-learn the tenant's rate limits from scratch. If you're worried, let it run for 30 more minutes and watch the Failed counter — if it's still zero, the job is fine.
What's next
- Auto-skipped files reference — the full pattern list and why typical sites shrink 40–60% after filtering.
- Executable file handling — why
.exeand.dllshow as Skipped and how to relax the policy. - Migration Rehearsal dry-run — validate a real run's plan before cutover night.
- Share a migration live view with your client — a read-only window into the running job.