Title: [High][reactive] Effect that writes a signal it reads recurses synchronously → stack overflow (no cycle guard) · Issue #166 · bQuery/bQuery · GitHub
Open Graph Title: [High][reactive] Effect that writes a signal it reads recurses synchronously → stack overflow (no cycle guard) · Issue #166 · bQuery/bQuery
X Title: [High][reactive] Effect that writes a signal it reads recurses synchronously → stack overflow (no cycle guard) · Issue #166 · bQuery/bQuery
Description: Severity: 🟠 High (robustness / self-DoS) Location src/reactive/internals.ts:54-60 (scheduleObserver), src/reactive/core.ts:48-56 (Signal.set), src/reactive/effect.ts:81-108 (observer — no re-entrancy guard). Description When batchDepth =...
Open Graph Description: Severity: 🟠 High (robustness / self-DoS) Location src/reactive/internals.ts:54-60 (scheduleObserver), src/reactive/core.ts:48-56 (Signal.set), src/reactive/effect.ts:81-108 (observer — no re-entran...
X Description: Severity: 🟠 High (robustness / self-DoS) Location src/reactive/internals.ts:54-60 (scheduleObserver), src/reactive/core.ts:48-56 (Signal.set), src/reactive/effect.ts:81-108 (observer — no re-entran...
Opengraph URL: https://github.com/bQuery/bQuery/issues/166
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[High][reactive] Effect that writes a signal it reads recurses synchronously → stack overflow (no cycle guard)","articleBody":"## Severity: 🟠 High (robustness / self-DoS)\n\n## Location\n[`src/reactive/internals.ts:54-60`](../blob/main/src/reactive/internals.ts#L54-L60) (`scheduleObserver`), [`src/reactive/core.ts:48-56`](../blob/main/src/reactive/core.ts#L48-L56) (`Signal.set`), [`src/reactive/effect.ts:81-108`](../blob/main/src/reactive/effect.ts#L81-L108) (observer — no re-entrancy guard).\n\n## Description\nWhen `batchDepth === 0`, `scheduleObserver` invokes the observer **synchronously** inside `Signal.set`. The effect observer has no \"currently running\" guard, so an effect that writes to a signal it also reads (with a changing value) re-enters itself until the stack overflows:\n\n```ts\neffect(() =\u003e { count.value = count.value + 1; });\n// read subscribes observer → write calls set → Object.is false →\n// scheduleObserver runs observer synchronously → writes again → …\n// → RangeError: Maximum call stack size exceeded\n```\n\nWrapping in `batch()` does **not** help: during `flushObservers`, `batchDepth` is already 0, so the re-write recurses synchronously. Mutually-recursive effects/computeds hit the same path. Mainstream reactive libraries (Vue, Solid) detect this cycle and warn/bail rather than crashing the tab.\n\n## Impact\nA single natural authoring mistake crashes the whole runtime (uncatchable `RangeError` unwinds the render). No untrusted input required, but the failure mode is a hard denial of service of the page.\n\n## Suggested fix\nAdd a re-entrancy / max-depth guard: track a per-observer `isRunning` flag (or an `activeObservers` set) and, when an observer is scheduled while already executing, either defer to a microtask or bail with a \"cyclic dependency detected\" warning (Vue-style depth counter). A max-depth counter on synchronous cascades is the minimal safe fix.\n\n---\n_Filed as part of a full-codebase security \u0026 correctness audit._\n","author":{"url":"https://github.com/JosunLP","@type":"Person","name":"JosunLP"},"datePublished":"2026-07-05T17:02:50.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/166/bQuery/issues/166"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:c5a58ba2-ab3e-78eb-a406-b40eb0bbe1a9 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | BE24:E21F7:AE44A6:B2196C:6A4DB5F4 |
| html-safe-nonce | dc76f24324558acb8019e9fa50965257f98d83f86809ef0364e731f164576c74 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCRTI0OkUyMUY3OkFFNDRBNjpCMjE5NkM6NkE0REI1RjQiLCJ2aXNpdG9yX2lkIjoiNTk4OTQwMjU5OTgwNzEwNDUwMCIsInJlZ2lvbl9lZGdlIjoic2VhIiwicmVnaW9uX3JlbmRlciI6InNlYSJ9 |
| visitor-hmac | c88d4cbffb31a81cda82798f9d623c59597f171c18eb7ec88c843d5d8e3abc45 |
| hovercard-subject-tag | issue:4813692978 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/bQuery/bQuery/166/issue_layout |
| twitter:image | https://opengraph.githubassets.com/ae351c58c617792cda07f37b1249821532edd3dbe27f6646c7b469ed60109bec/bQuery/bQuery/issues/166 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/ae351c58c617792cda07f37b1249821532edd3dbe27f6646c7b469ed60109bec/bQuery/bQuery/issues/166 |
| og:image:alt | Severity: 🟠 High (robustness / self-DoS) Location src/reactive/internals.ts:54-60 (scheduleObserver), src/reactive/core.ts:48-56 (Signal.set), src/reactive/effect.ts:81-108 (observer — no re-entran... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | JosunLP |
| hostname | github.com |
| expected-hostname | github.com |
| None | 06b8a6144231bf3a234f1c2e9993861e07ce98a905912b114aa386c2d7e84b33 |
| turbo-cache-control | no-preview |
| go-import | github.com/bQuery/bQuery git https://github.com/bQuery/bQuery.git |
| octolytics-dimension-user_id | 256381806 |
| octolytics-dimension-user_login | bQuery |
| octolytics-dimension-repository_id | 1139284244 |
| octolytics-dimension-repository_nwo | bQuery/bQuery |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1139284244 |
| octolytics-dimension-repository_network_root_nwo | bQuery/bQuery |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 32f7b614aca06e6bbd89842b1370df1328264f68 |
| ui-target | canary-1 |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width