Improve CLI sync error messages for sites that can't be synced - #4202
Conversation
Report the specific syncSupport condition and next step (enable hosting features, upgrade plan, etc.) instead of a generic failure or a raw internal state identifier, including in the pull-reprint flow for Business-plan sites awaiting Atomic transfer.
… leak Simplify the lone-non-syncable check in resolveSourceSite (nonSyncable is provably the whole list there), and give getSyncSupportLabel an already-connected case plus a non-leaking default so the picker no longer shows a raw state identifier.
software_version is only returned for Atomic/Jetpack sites, but the /me/sites schema required it, so every Simple site (Business plans awaiting Atomic transfer, plus Free/Personal plans) failed validation and was silently dropped. They never appeared in the list, so pull-reprint --url reported them as not connected and the sync UI could not surface their needs-transfer/needs-upgrade guidance. Make the field optional.
There was a problem hiding this comment.
Pull request overview
This PR fixes sync site classification for WordPress.com “Simple” sites (e.g., Business sites not yet Atomic-transferred, plus Free/Personal plans) by relaxing the /me/sites response schema so these sites aren’t dropped during validation, and it improves CLI sync-related error messaging by centralizing per-state, actionable errors (including links for next steps).
Changes:
- Make
options.software_versionoptional in the shared/me/sitesZod schema so Simple sites are retained and can be classified. - Add coverage ensuring Simple sites are preserved and that
wpVersionis undefined when the API omitssoftware_version. - Centralize CLI non-syncable-site messaging via
getSyncSupportError()and use it inpull-reprint(including the “only one site and it’s not pullable” case), plus improve picker labels.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/common/types/sync.ts | Makes options.software_version optional so Simple sites don’t fail schema parsing. |
| packages/common/lib/sync/tests/transform-sites.test.ts | Adds tests to ensure Simple sites are retained and wpVersion behavior matches API omission/presence. |
| apps/cli/lib/sync-site-picker.ts | Introduces getSyncSupportError() and improves disabled-site labels to avoid surfacing raw internal states. |
| apps/cli/commands/tests/pull-reprint.test.ts | Updates/adds assertions to validate the new per-state error messages in pull-reprint source resolution. |
| apps/cli/commands/pull-reprint.ts | Routes non-syncable cases through the centralized error helper and improves the “no pullable sites” messaging for single-site accounts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
📊 Performance Test ResultsComparing 1b86324 vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
| // WordPress.com only returns software_version for Atomic/Jetpack | ||
| // sites; Simple sites (e.g. Business plans not yet transferred to | ||
| // Atomic, or Free/Personal plans) omit it. Requiring it here would | ||
| // silently drop every Simple site from the synced-sites list. | ||
| software_version: z.string().optional(), |
There was a problem hiding this comment.
The list of sites returned should match the existing list returned by the pull command, so we can mimic that functionality. I think simple sites are not returned now as they are not supported, so I'd say that it's fine not to return them.
There was a problem hiding this comment.
Good point on keeping feature parity, but I think this change preserves it. The change is in the shared fetchSyncableSites, so pull, push, pull-reprint and the Desktop all stay consistent.
Earlier, simple sites weren’t deliberately filtered out, it was a schema bug. options.software_version was marked required, but WordPress.com only returns it for Atomic/Jetpack sites, so every Simple site failed validation and was dropped.
IMO keeping them in the list is a small UX enhancement. Rather than hiding a site the customer paid for, we surface it as non-syncable with a suggested next step (“enable hosting features” / “upgrade your plan”).
There was a problem hiding this comment.
That sounds like a great improvement to me, if the next step is clear to the user. Thanks for improving this!
gavande1
left a comment
There was a problem hiding this comment.
Thanks for improving the error messages. I tested this and it works as described. LGTM 🚀
There are a few comments on the wording, but approving to unblock you.
Co-authored-by: Rahul Gavande <rahul.gavande@automattic.com>
… a specific plan Syncability depends on the plan including hosting features (wp-cloud), not on the Business plan specifically, so the needs-upgrade message no longer names a plan tier.
Related issues
How AI was used in this PR
I used Claude to investigate the issue, trace the pull-reprint, push, and legacy pull flows, write the changes and tests. I reviewed and validated the messaging and the logic myself.
Proposed Changes
Trying to sync a Business-plan site that hasn't been Atomic transferred yet (or a Free/Personal site) failed with a misleading "This URL is not a WordPress.com or Pressable site connected to your account", even for sites you own. The root cause is that WordPress.com only returns
options.software_versionfor Atomic/Jetpack sites, but the shared/me/sitesschema marked it required, so every Simple site failed validation and was silently dropped from the list before it could be classified. Because those sites never appeared, the reprint pull couldn't resolve them and the sync UI couldn't show their real status.This PR:
software_versionoptional so Simple sites are retained and correctly classified as needs-transfer or needs-upgrade. This also repairs the Desktop sync list, which drops sites through the same schemaTesting Instructions
npm run cli:buildSTUDIO_ENABLE_PULL_REPRINT=true node apps/cli/dist/cli/main.mjs pull-reprint --path <local-site> --url <site-url>wordpress.com/hosting-features/<id>.wordpress.com/plans/<id>.studio pushorstudio pullcommands with a mix of sites and confirm the Simple sites now appear as non-syncable entries in the picker with a readable reason (e.g. Transfer required, Plan upgrade required).Pre-merge Checklist