Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
The error occurs because the callback is running outside Cypress’s normal command queue. Cypress commands such as cy.get(), cy.wait(), and cy.task() belong in a test’s command chain, not inside a request or event callback. Keep the callback synchronous: inspect or change the request with its supplied req object, then pass data back to the test and use Cypress commands later.
First, identify which callback you mean
Developers sometimes call a cy.intercept() route handler an “onRequest handler.” Cypress calls that callback a routeHandler. It receives a req object for an application request matched by the intercept.
A separate callback family is registered with Cypress.on(), such as a listener for a Cypress event. These listeners are not the same API as an intercept route handler. However, the important constraint is the same: Cypress commands do not run there as they do in the test body. The event documentation explicitly says that Cypress event callbacks execute outside the normal command queue and do not support cy commands, assertions, or cy.task().
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →So if your callback is named onRequest, determine how it is registered before changing the code. If it is passed to cy.intercept(), use the intercept request and response APIs. If it is a Cypress.on() listener, keep it synchronous and move any Cypress work back into the test chain.
#1 Best Overall
Why calling cy.* there fails
Cypress test commands are queued and run in order by Cypress. A callback that runs outside that queue cannot insert a command into the test’s normal execution flow. That is why placing a Cypress command in the callback can cause an error, fail to behave as expected, or leave you trying to use a command in the wrong execution context.
Adding await does not fix the context. Cypress commands are not Promises that JavaScript can await; Cypress has a .then() command, but that does not turn Cypress commands into native Promises or make an event callback part of the Cypress queue. Use await only for an actual Promise-based API where the callback’s context supports that work—not as a way to make cy.get() or cy.wait() valid inside a handler.
A pattern that causes the problem
cy.intercept('POST', '/users', (req) => {
cy.task('recordRequest', req.body)
cy.wait(500)
})
The callback is being invoked to handle a matching request. It is not a test-body command chain. The same restriction applies to cy.get(), cy.request(), and Cypress assertion commands called from inside the callback.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallUse the route handler for request work
Keep an intercept route handler focused on the request itself. You can inspect request properties such as its body, headers, URL, and method; change supported properties; or use the handler’s lifecycle methods to stub, pass through, redirect, or fail the request.
Rank #2
For synchronous checks, ordinary JavaScript and Chai’s expect are appropriate. This example checks a request body, adds a header, and gives this request an alias:
cy.intercept('POST', '/users', (req) => {
expect(req.body).to.include('Acme Company')
req.headers['x-test-mode'] = 'true'
req.alias = 'createUser'
}).as('users')
cy.wait('@createUser')
.its('request.body')
.should('include', 'Acme Company')
The expect() call is an ordinary synchronous assertion, not a queued Cypress assertion command. The final .should(), by contrast, is a Cypress command and belongs in the test chain. That distinction matters: not every assertion-looking expression has the same execution model.
Choose the request API that matches the job
req.reply()lets the route handler provide a stubbed response.req.continue()lets the request proceed to the real server; its callback can inspect or modify the real response.req.destroy()forces a network error.req.redirect()redirects the request.req.on()attaches a handler to a response lifecycle event.
Use these APIs when the job is to affect or observe the application request matched by cy.intercept(). Do not replace them with a Cypress command inside the route handler.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Move test work back into the command chain
If the test needs to record data, make a later assertion, or call a task, capture the request information or give the request an alias in the handler. Then use cy.wait() and any other Cypress commands after the application has made the request.
Rank #3
let capturedBody
cy.intercept('POST', '/users', (req) => {
capturedBody = req.body
req.alias = 'createUser'
})
cy.wait('@createUser').then((interception) => {
expect(interception.request.body).to.deep.equal(capturedBody)
cy.task('recordRequest', interception.request.body)
})
Here, the handler saves plain JavaScript data and assigns an alias. The test’s queued cy.wait() yields the interception object; the chained callback is where the test can use cy.task(). This handoff separates work at request time from work that belongs in the test’s command queue.
Choose what to hand off
- Use an alias when the test should wait for a matching request and examine the resulting interception.
- Store plain data when the handler needs to preserve a value for a later test step. Keep the stored value simple and ensure the later step runs after the relevant request.
- Use both when you want the named wait to establish timing and a saved value to compare or use later.
Do not call cy.wait() from the handler to create this timing. Put it after the intercept is registered, in the test chain.
Inspect or change a response at the right lifecycle stage
When the issue concerns a response rather than the outgoing request, use the intercept lifecycle rather than trying to wait for it with a Cypress command inside the handler.
Recommended Free Tools
req.continue((res) => { ... })passes the request through and provides the real response for inspection or modification.req.on('before:response', callback)runs before response handlers.req.on('response', callback)runs afterbefore:responseandreq.continuehandlers, but before the response is sent to the browser.req.on('after:response', callback)runs after delivery. At that point, it cannot change the response delivered to the browser.
The response object exposes body, headers, statusCode, and statusMessage. The supported response phases allow modifications to the body, headers, and status code to affect the delivered response. Pick a phase based on whether you need to inspect a value, change the response before delivery, or observe it after delivery.
Rank #4
Use cy.request() for a different job
cy.request() makes a direct API request from the Cypress Node process. It is useful for test setup, seeding data, or verifying an API endpoint directly, and it must be chained from cy in the test command chain.
It is not a workaround for calling Cypress from a handler. A direct cy.request() also bypasses routes configured with cy.intercept(), so it does not exercise the same intercepted application-request path. Choose it when the test itself needs to call an endpoint directly; use cy.intercept() when you need to observe or affect a request made by the application.
Troubleshoot the common failure modes
“Cypress commands cannot be invoked from this callback”
Cause: A cy.* command is running inside a Cypress.on() listener or an intercept route handler. Fix: Keep request-level work synchronous in the handler; capture data or assign an alias, then run the Cypress command after the callback in the test chain.
The handler uses await cy.wait() or await cy.task()
Cause: await does not turn Cypress commands into Promises and does not move the callback into Cypress’s queue. Fix: Remove the attempted await and put the command in the test chain. For response work, use the relevant req lifecycle API.
A cy.wait('@alias') never reaches the handler’s intended step
Cause: The wait has been placed inside the handler, or the test is trying to make the handler control the Cypress queue. Fix: Register the intercept in the test, trigger the application action that makes the request, and put cy.wait('@alias') in the test chain where it can yield the interception.
A request handler needs to call cy.task()
Cause: cy.task() is being used as if it were a synchronous request callback operation. Fix: Save or alias the relevant request data, then call cy.task() from a later test-chain step, such as the callback chained from cy.wait().
The test queues a Cypress command and returns a different value
Cause: Cypress reports an error when a callback queues a Cypress command and also returns a different, non-undefined value. Commands are queued for later execution, so the explicit return can conflict with that flow. Fix: Remove the conflicting return or move the Cypress command into the test chain. Do not try to resolve this by adding await.
The test needs to set up data through an endpoint
Cause: The test is trying to perform setup by calling cy.request() from an intercept callback. Fix: Run cy.request() in the test chain before or after the relevant application action, as appropriate. Remember that it bypasses routes configured with cy.intercept().
Or skip the browser setup
If what you need is a website screenshot rather than a Cypress test of an application request, ScreenshotNeo can capture a URL with one GET request. This does not fix a Cypress callback error or replace an intercept test; it is a separate option when your goal is simply to obtain a screenshot or PDF without setting up browser automation. See the ScreenshotNeo website and API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; those steps can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
A quick decision guide
| What you need to do | Use | Where it runs |
|---|---|---|
| Inspect, change, stub, or pass through an application request | cy.intercept() with req APIs |
Route handler; keep operations synchronous |
| Wait for an application request and inspect what happened | cy.wait('@alias') |
Test command chain after the request is triggered |
| Record intercepted data in a task | cy.task() after the handoff |
Test command chain, for example after cy.wait() |
| Call an endpoint directly for setup or verification | cy.request() |
Test command chain; it bypasses cy.intercept() |
| React to a Cypress event | Cypress.on() with synchronous callback work |
Outside the normal Cypress command queue |
Summary
Treat an intercept or event callback as a boundary, not as another place to extend the Cypress command chain. Use the callback’s supplied request and response APIs for synchronous network work; hand needed data back through an alias or plain JavaScript value; and put cy.wait(), cy.task(), direct API calls, and queued assertions in the test chain. Neither await nor a different Cypress command removes that boundary.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

