Title
Regression in @percy/cli@1.32.0 - 1.32.2: sync Automate snapshots fail with {"error":"upload is not async iterable"} (works in 1.31.8 - 131.14)
The problem
After upgrading @percy/cli from 1.31.8 to 1.32.2, synchronous Percy-on-Automate snapshots fail.
Our Java Selenium tests call:
new Percy(driver).screenshot(name, options) // with sync: true
(sync: true is required for inline comparison validation.)
Instead of comparison results, the SDK returns:
{"error":"upload is not async iterable"}
Example snapshot: “View All default layout”.
On 1.31.8, the same flow works: sync returns full comparison JSON with "status":"success", dashboard URLs, and diff-info.
Screenshot capture on BrowserStack Automate succeeds in both cases; failure occurs in the CLI sync upload path after capture.
We believe this is a regression in sync handling of /percy/automateScreenshot introduced while fixing Maestro sync (commit 545d498 in PR #2217). The code uses for await (const _ of upload) on percy.upload(), but percy.upload is wrapped in percy.js to return a Promise via generatePromise(). The raw async generator appears to be percy.yield.upload(). Iterating a Promise causes this exact error.
Working (1.31.8):
const snapshotPromise = new Promise((resolve, reject) =>
percy.upload(comparisonData, { resolve, reject }, 'automate'));
Broken (1.32.2):
const upload = percy.upload(comparisonData, { resolve, reject }, 'automate');
for await (const _ of upload) { /* drain */ } // upload is a Promise, not async iterable
The same for await pattern appears in sync branches of /percy/comparison and /percy/maestro-screenshot in 1.32.2.
Workaround: Pin @percy/cli@1.31.8.
Suggested fix: Drain percy.yield.upload() instead of percy.upload(), or revert sync Automate routes to the 1.31.8 Promise pattern.
Environment
- Node version:
14.21.3 (CodeBuild; npm warns image-size@1.2.1 wants Node >=16)
- @percy/cli version:
1.32.2 (broken), 1.31.8 (works)
- Percy SDK version:
io.percy:percy-java-selenium:2.1.1
- Build/snapshot reference: https://percy.io/76a47c69/web/LPPortal-Desktop2-eb42b0fd/builds/51116938
(1.31.8 build with visual diff on “View All default layout”; sync path succeeded)
- OS version: Linux (Amazon Linux 2, CodeBuild
4.14.355-282.733.amzn2.x86_64)
- Shell/CLI: bash (
npx percy exec --verbose -- ./gradlew test -Pvisual ...)
Details
Setup:
- Percy-on-Automate via BrowserStack (
-Premote=browserstack)
- Run command:
npx percy exec --verbose -- ./gradlew test -Pvisual -Penv=qa -Pbrowser=Chrome ...
- Java test uses sync screenshots:
Map<String, Object> options = new HashMap<>();
options.put("fullPage", true);
options.put("sync", true);
JSONObject json = new Percy(getDriver()).screenshot(snapshotName, options);
Observed on 1.32.2:
- Output for snapshot “View All default layout”:
{"error":"upload is not async iterable"}
- Validation fails because response has no
status: success / screenshot payload.
Observed on 1.31.8 (same test/snapshot):
- Full sync comparison JSON returned with
"status":"success".
- Percy CLI logs show expected flow:
- Snapshot taken
- Creating snapshot
- Waiting for snapshot completion
- Polling comparison status
Scope:
- Affects sync Automate snapshots (
sync: true)
- Likely affects sync paths on
/percy/comparison and /percy/maestro-screenshot too (same pattern)
- Non-sync snapshots may still work (not fully verified)
References:
Debug logs
1.31.8 (working) excerpt:
+ npm install --save-dev @percy/cli@1.31.8
+ @percy/cli@1.31.8
[percy:webdriver-utils:captureScreenshot] [View All default layout] : Comparison Data: {...}
[percy:core] Snapshot taken: View All default layout
[percy:client] Creating snapshot: View All default layout...
[percy:core] Waiting for snapshot 'View All default layout' to be completed
[percy:core:wait-for-job] Polling for comparison status in 5000ms
Json object for snapshot 'View All default layout':
{"snapshot-name":"View All default layout",...,"status":"success",...}
1.32.2 (broken) excerpt:
Json object for snapshot 'View All default layout':
{"error":"upload is not async iterable"}
(Full CodeBuild logs available on request; Percy CLI verbose logging enabled.)
Code to reproduce issue
Minimal reproduction concept:
- Run visual tests on BrowserStack Automate with
percy exec.
- Use
io.percy:percy-java-selenium >= 2.0.4 with sync: true.
- Install
@percy/cli@1.32.2 → sync snapshots return:
{"error":"upload is not async iterable"}
- Pin
@percy/cli@1.31.8 → same tests return valid sync comparison JSON.
Java test pattern:
Map<String, Object> options = new HashMap<>();
options.put("fullPage", true);
options.put("sync", true);
JSONObject json = new Percy(getDriver()).screenshot("View All default layout", options);
// 1.32.2: {"error":"upload is not async iterable"}
// 1.31.8: includes status, screenshots, dashboard-urls, diff-info
CI install line that reproduces:
npm install --save-dev @percy/cli@1.32.2
npx percy exec --verbose -- <your-test-runner-with-sync-percy-screenshots>
We do not yet have a minimal public repro repo; happy to provide additional logs or a stripped-down example if helpful.
Title
Regression in
@percy/cli@1.32.0 - 1.32.2: sync Automate snapshots fail with{"error":"upload is not async iterable"}(works in 1.31.8 - 131.14)The problem
After upgrading
@percy/clifrom 1.31.8 to 1.32.2, synchronous Percy-on-Automate snapshots fail.Our Java Selenium tests call:
(
sync: trueis required for inline comparison validation.)Instead of comparison results, the SDK returns:
{"error":"upload is not async iterable"}Example snapshot: “View All default layout”.
On 1.31.8, the same flow works:
syncreturns full comparison JSON with"status":"success", dashboard URLs, and diff-info.Screenshot capture on BrowserStack Automate succeeds in both cases; failure occurs in the CLI sync upload path after capture.
We believe this is a regression in sync handling of
/percy/automateScreenshotintroduced while fixing Maestro sync (commit545d498in PR #2217). The code usesfor await (const _ of upload)onpercy.upload(), butpercy.uploadis wrapped inpercy.jsto return a Promise viageneratePromise(). The raw async generator appears to bepercy.yield.upload(). Iterating a Promise causes this exact error.Working (1.31.8):
Broken (1.32.2):
The same
for awaitpattern appears in sync branches of/percy/comparisonand/percy/maestro-screenshotin 1.32.2.Workaround: Pin
@percy/cli@1.31.8.Suggested fix: Drain
percy.yield.upload()instead ofpercy.upload(), or revert sync Automate routes to the 1.31.8 Promise pattern.Environment
14.21.3(CodeBuild; npm warnsimage-size@1.2.1wants Node >=16)1.32.2(broken),1.31.8(works)io.percy:percy-java-selenium:2.1.1(1.31.8 build with visual diff on “View All default layout”; sync path succeeded)
4.14.355-282.733.amzn2.x86_64)npx percy exec --verbose -- ./gradlew test -Pvisual ...)Details
Setup:
-Premote=browserstack)Observed on 1.32.2:
{"error":"upload is not async iterable"}status: success/ screenshot payload.Observed on 1.31.8 (same test/snapshot):
"status":"success".Scope:
sync: true)/percy/comparisonand/percy/maestro-screenshottoo (same pattern)References:
v1.31.8...v1.32.2(api.js)545d498api.js @ v1.32.2(searchautomateScreenshot)percy.js @ v1.32.2(this[m] = (...args) => generatePromise(method(...args)))Debug logs
1.31.8 (working) excerpt:
1.32.2 (broken) excerpt:
(Full CodeBuild logs available on request; Percy CLI verbose logging enabled.)
Code to reproduce issue
Minimal reproduction concept:
percy exec.io.percy:percy-java-selenium >= 2.0.4withsync: true.@percy/cli@1.32.2→ sync snapshots return:{"error":"upload is not async iterable"}@percy/cli@1.31.8→ same tests return valid sync comparison JSON.Java test pattern:
CI install line that reproduces:
We do not yet have a minimal public repro repo; happy to provide additional logs or a stripped-down example if helpful.