Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SecurityError: Attempt to use history.replaceState() more than 100 times per 30 seconds #365

Closed
Rich-Harris opened this issue Feb 3, 2021 · 18 comments · Fixed by #2749
Closed
Labels
bug Something isn't working
Milestone

Comments

@Rich-Harris
Copy link
Member

We've been seeing this in production, via Sentry — almost exclusively on iPhones. I assume it's related to this:

// There's no API to capture the scroll location right before the user
// hits the back/forward button, so we listen for scroll events
let scroll_timer;
addEventListener('scroll', () => {
clearTimeout(scroll_timer);
scroll_timer = setTimeout(() => {
// Store the scroll location in the history
// This will persist even if we navigate away from the site and come back
const new_state = {
...(history.state || {}),
'sveltekit:scroll': scroll_state()
};
history.replaceState(new_state, document.title, window.location);
}, 50);
});

@Rich-Harris Rich-Harris added the bug Something isn't working label Feb 3, 2021
@benmccann
Copy link
Member

That's surprising. I would expect the clearTimeout to prevent that. Unfortunately I don't have an iPhone to be able to test why debouncing isn't working there

@antony
Copy link
Member

antony commented Feb 3, 2021

@benmccann we have browserstack :)

@GrygrFlzr
Copy link
Member

Does this also happen on macOS? I have access to multiple iPhones, iPads, and a Macbook I can use to test. There may also be a difference between iOS WebView vs iOS Safari.

Possibly another real world case, although I'm not 100% on it yet: https://www.reddit.com/r/sveltejs/comments/lo2560/unofficial_documentation_for_sveltekit_made_using/go7wt6y/?context=3, seems like it may be causing hilariously low framerates when scrolling.

I'm wondering if it's possible such that multiple scroll events trigger at the same time, such that a race condition occurs:

  1. Scroll event 1 triggers
  2. Scroll event 2 triggers
  3. Scroll event 1 calls clearTimeout on null
  4. Scroll event 2 calls clearTimeout on null
  5. Scroll event 1 calls setTimeout
  6. Scroll event 2 calls setTimeout
  7. Scroll event 3 triggers
  8. Scroll event 3 calls clearTimeout on event 2
  9. Timeout 1 triggers, so does timeout 3

What if we push the timeouts into an array and call clearTimeout on each of those?

@antony
Copy link
Member

antony commented Feb 22, 2021

In case it's useful, I also see this on production, with Sentry - using Sapper, so we shouldn't be looking for something Kit specific.

Looks like an issue from Sapper got carried over to the Svelte Kit codebase. I'll dump any useful info here when I look it up later today.

@benmccann
Copy link
Member

I'm surprised you'd be seeing this in Sapper as well because this section of code was completely rewritten in Kit

@Rich-Harris Rich-Harris added this to the 1.0 milestone Mar 5, 2021
@zackify
Copy link

zackify commented Mar 23, 2021

What if you changed it to only run every 500ms? Then it would only run a max of 60 times in 30 seconds. I feel like that is still pretty frequent for restoring the scroll position later.

@benmccann
Copy link
Member

It should not be running when continuously moving the mouse or when not moving the mouse, but only when the mouse was moving and then stops. Changing it to 500s sounds like a copout instead of really understanding the issue as to why debouncing isn't working here.

@zackify
Copy link

zackify commented Mar 23, 2021

I see what you mean!

@Rich-Harris Rich-Harris modified the milestones: 1.0, post-1.0 May 1, 2021
@pago
Copy link

pago commented Jun 15, 2021

Not entirely sure if it should go here or in a separate issue. Happy to move it to a separate issue if needed.

I'm observing the same issue mentioned here but I also have some (iOS only) errors about pushState in my Sentry log.

SecurityError: Attempt to use history.pushState() more than 100 times per 30 seconds

Might be related somehow.

@philippdormann
Copy link

seeing these issues in production on iOS 14.7.1 devices (iPhone 12 mini - "iPhone13,1")

SecurityError: Attempt to use history.replaceState() more than 100 times per 30 seconds
SecurityError: Attempt to use history.pushState() more than 100 times per 30 seconds

@acoyfellow
Copy link

Can confirm I'm picking this up via Sentry too:

SecurityError: Attempt to use history.replaceState() more than 100 times per 30 seconds

Mobile Safari
Version:14.1.2

iOS
Version:14.7.1

iPhone

@si3nloong
Copy link
Contributor

May be we can refer to this solution.

https://github.com/ampproject/amphtml/pull/23938/files

@myisaak
Copy link

myisaak commented Nov 4, 2021

Check out my PR on this issue: #2738

@bluwy
Copy link
Member

bluwy commented Nov 5, 2021

I tested this on my iphone today and I discovered that ios emits the scroll event later than other browsers. Intervals between scroll events rapidly fluctuate between 30 - 150ms. And an easy way to aggressively trigger this bug is to quickly scroll up and down, that would consistently give 200-300ms.

With these said, our debounce function runs at a 50ms interval, which explains how the security error was caused, because we essentially had no debouncing at all. I'll submit a PR to increase it to 200ms as that gives the least false positives.

@sundarrajendran
Copy link

What is the fix for this issue. I am also getting the same error. can anyone please help?
Attempt to use history.pushState() more than 100 times per 30 seconds

@TheBlckbird
Copy link
Contributor

This is safari specific

@mprync
Copy link

mprync commented Oct 26, 2023

This is still happening on Safari and potentially iOS but it is specific to Safari.

@meghbhalerao
Copy link

I am facing the same issue on safari -
Screenshot 2023-12-07 at 11 10 18 PM
Could someone please help me with this?
Thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.