[BUG] Empty ruleset still injects ~2000ms delay on every fetch/XHR request (v26.7.27)
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- javascript
- Domain
- tooling
Research direction
Start by reproducing the delay with an empty ruleset, then inspect the interceptor in client.cs.js, especially the patched fetch and XMLHttpRequest paths and the W() and B() entry points. Done means requests with empty delayRules, requestRules, and responseRules complete without the ~2000ms delay while configured rules continue to work.
Written by the indexing model from the issue text.
Description
Issue 草稿:Requestly Chrome 扩展在规则为空时对所有 fetch/XHR 请求施加 ~2000ms 延迟
提交地址:https://github.com/requestly/requestly/issues/new
标题建议:[BUG] Empty ruleset still injects ~2000ms delay on every fetch/XHR request (v26.7.27)
Title
[BUG] Empty ruleset still injects ~2000ms delay on every fetch/XHR request (v26.7.27)
Summary
With zero rules configured (no Delay / Request / Response rules — window.__REQUESTLY__ shows all rule arrays empty), the Requestly Chrome extension's content-script interceptor still forces a constant ~2000ms delay on every fetch and XMLHttpRequest on every page it injects into. Disabling the extension instantly restores normal (<30ms) latency.
The delay is applied in JS (not at the network/DNR layer): Resource Timing shows TTFB of 10–21ms, but await fetch() resolves after ~2010–2050ms. An iframe whose contentWindow.fetch was not patched by Requestly completes the same request in ~24ms.
Client
- Desktop — macOS (Darwin 25.5.0)
- Desktop — Windows
- Desktop — Linux
- CLI
Protocol
- HTTP / REST (any protocol — delay is protocol-agnostic)
- GraphQL
- WebSocket
- Socket.IO
- gRPC
- MQTT
- Not protocol-specific
Feature Area
- Request editor
- Collections
- Environments & Variables
- Mock Server
- API Design (OpenAPI)
- Collection Runner
- Import / Export
- Authentication
- Scripts
- Other — HTTP Interceptor (fetch/XHR monkey-patch in content script)
App Version
- Extension: Requestly
26.7.27(MV3, extension IDmdnleldcmiljblolnjhpnblkcekpdkpa) - Previous version present on disk:
26.6.10(downgrade path available for bisect) - Browser: Google Chrome 150.0.0.0 (macOS)
- OS: macOS (Darwin 25.5.0)
Steps to Reproduce
- Install Requestly v26.7.27 in Chrome.
- Ensure no rules are configured — no Delay, no Request, no Response rules. (A freshly reset Requestly account / local state with zero rules reproduces this.)
- Open any website where Requestly's content script injects (any
http://*orhttps://*page, excludingapp.requestly.com). - From DevTools Console on that page, run:
const t = performance.now(); await fetch('/any-path').then(r => r.text()); console.log(performance.now() - t); - Observe the logged duration is consistently ~2000ms, regardless of the path or whether the resource even exists (a 404 path is also delayed ~2000ms).
Minimal reproduction snippet (run in page console)
// 1. Confirm no rules are loaded
console.log(window.__REQUESTLY__);
// → { sharedState: {}, delayRules: [], requestRules: [], responseRules: [] } ← ALL EMPTY
// 2. Confirm fetch is monkey-patched by Requestly
console.log(window.fetch.toString());
// → async(...r)=>{...const u=W({url:i,method:a,type:"fetch",...}); u&&await B(u.delay);...}
// ^ W() returns truthy even with empty rulesets → awaits ~2000ms
// 3. Measure delay — constant ~2000ms on any request
for (let i = 0; i < 5; i++) {
const t0 = performance.now();
await fetch('/api/logs/stats').then(r => r.text()).catch(() => {});
console.log('run', i, Math.round(performance.now() - t0) + 'ms');
}
// → ~2018, ~2014, ~2014, ~2012, ~2015 (all ~2000ms)
// 4. Control: an iframe whose fetch was NOT patched by Requestly
const iframe = document.createElement('iframe');
iframe.srcdoc = '<html><body></body></html>';
document.body.appendChild(iframe);
await new Promise(r => iframe.onload = r);
const t = performance.now();
await iframe.contentWindow.fetch('/api/logs/stats').then(r => r.text());
console.log('iframe (unpatched):', Math.round(performance.now() - t) + 'ms');
// → ~24ms ← normal!
iframe.remove();
Expected Behavior
With an empty ruleset (delayRules: [], requestRules: [], responseRules: []), the interceptor's match function W({url, method, type, ...}) should return undefined/null, so the u && await B(u.delay) guard short-circuits and no delay is applied. Every request should complete at native speed (~10–50ms for local).
Actual Behavior
W() returns a truthy value (an object with delay ≈ 2000) even when no rules exist, so await B(u.delay) executes and stalls every request by ~2000ms.
Measured evidence
| Measurement | Value | Notes |
|---|---|---|
curl https://<site>/api/logs (bypasses extension) |
18–52 ms | Backend & network are fast |
await fetch() from page console |
2010–2050 ms | Constant, independent of payload |
fetch('/404-nonexistent') |
2006 ms | Delay applies to non-existent paths too |
fetch('/favicon.svg'), static image |
2015–2057 ms | Applies to all resources on the domain |
Resource Timing responseStart - requestStart (TTFB) |
10–21 ms | Network layer is fast — delay is in JS |
iframe contentWindow.fetch (unpatched by Requestly) |
24 ms | Bypassing the interceptor = normal |
window.fetch.toString() |
monkey-patched | async(...r)=>{...await B(u.delay)...} |
XMLHttpRequest.prototype.open/send |
monkey-patched | contains rqProxyXhr, await B(s.delay) |
window.__REQUESTLY__ |
{delayRules:[], requestRules:[], responseRules:[]} |
No rules configured |
Parallel vs serial behavior
Issuing 3 concurrent fetch calls resolves in ~2046ms total (not ~6000ms), indicating the delay is awaited in parallel per-request rather than serialized — consistent with a per-request await B(delay) in each intercepted Promise.
Additional Context
Why this was hard to diagnose (and a clue for the team)
Because the delay is injected in the JS layer and Resource Timing reports honest network timings, the symptom looks identical to "my backend is slow" — but the backend is fine (curl confirms <50ms). The constant ~2000ms floor regardless of path/status, plus the empty __REQUESTLY__ ruleset, are the fingerprints.
Historical note
Issue #127 ("Allow Delay Network Requests Rule greater than 2000ms") suggests 2000 may be a default/ceiling value in the delay code path. The fact that the observed delay sits right at ~2000ms — and is applied even with no delay rule defined — strongly suggests a code path where a default delay value is applied when the matcher has no rule but still returns a truthy object.
Likely code location
The interceptor lives in the content script client.cs.js (matches http://*/*, https://*/*, run_at: document_start). The patched fetch and XMLHttpRequest.prototype.open/send reference an internal W() (returns matched delay rule pair) and B() (executes the delay). When the ruleset is empty, W() should return falsy but appears to return a truthy {delay: ~2000}.
Workaround
Disabling the Requestly extension immediately restores normal request latency.
Regression bisect candidate
Version 26.6.10 is still present on disk alongside 26.7.27. If the team can't reproduce on 26.6.10, this is likely a regression introduced in 26.7.x. I can run a bisect if helpful.
Environment
- Extension: Requestly 26.7.27 (ID:
mdnleldcmiljblolnjhpnblkcekpdkpa) - Browser: Chrome 150.0.0.0
- OS: macOS (Darwin 25.5.0)
- Rules configured: none (empty ruleset confirmed via
window.__REQUESTLY__)
提交后建议附带的诊断数据(可选,增强说服力)
如官方需要,可提供:
client.cs.js中W()与B()的反混淆实现(可由官方自行定位)- 完整的 Resource Timing 截图(TTFB 10ms vs fetch 2018ms 的对比)
- 禁用扩展前后
await fetch()的耗时对比曲线
- Dominant language
- No language data
- Stars
- 6.8k
- Forks
- 694
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from requestly/requestly
-
[BUG] login Openissue type:bug
Difficulty 4/5 3-5 days Newbie friendliness 35/100
-
issue type:feature
Difficulty 4/5 3-5 days Newbie friendliness 55/100
-
issue type:bug
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
issue type:bug
Difficulty 3/5 1-2 days Newbie friendliness 38/100
All issues in requestly/requestly
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
newrelic-experimental/preflight#793 · 1 comment ·
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
babalae/bettergi-scripts-list#3674 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
caddyserver/caddy#8046 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
zilliztech/memsearch#759 ·
-
comp/cron P2 sweeper:risk-automation type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
NousResearch/hermes-agent#117792 · 1 comment ·