Skip to content

fix(rate-limits): skip a huge Cursor desktop WAL on the main thread - #24366

Closed
innocarpe wants to merge 3 commits into
stablyai:mainfrom
innocarpe:fix-24360-cursor-wal-skip
Closed

innocarpe wants to merge 3 commits into
stablyai:mainfrom
innocarpe:fix-24360-cursor-wal-skip

Conversation

@innocarpe

Copy link
Copy Markdown
Contributor

Description

Switching back to Orca froze the UI for several seconds on machines whose Cursor state.vscdb has a huge uncheckpointed WAL. The desktop-login probe opens that database with node:sqlite on the main thread. The 250 ms timeout only covers a lock wait, so SQLite still scans the whole WAL before the first query returns.

Focused fix

In:

  • Before opening the database, skip the read when state.vscdb-wal is larger than 32 MiB.
  • The session reader already ignores a desktop read error, so this does not raise the usage alert. Keychain and CLI logins are unchanged.

Out:

  • Moving the probe to a worker.
  • Checkpointing or copying Cursor's database.

Preserves

A missing database is still missing. A normal database, with no WAL or a small one, still returns the stored access token, email, and membership fields. A busy lock on a small database still uses the existing timeout.

Evidence

node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts --cache false src/main/rate-limits/cursor-desktop-state-db.test.ts

The test reads a token from a small database, reports a missing file, and refuses a database whose WAL is just over 32 MiB without treating that file as a successful login.

User-regression-tradeoffs

Someone whose only Cursor login lives in a WAL larger than 32 MiB no longer gets that desktop session automatically. They can still sign in with cursor-agent login. The freeze on every focus is the reported failure.

Fixes #24360

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 6955e785-c93b-468b-bef0-8af22a78bfde

📥 Commits

Reviewing files that changed from the base of the PR and between 9638785 and 72eb000.

📒 Files selected for processing (1)
  • src/main/rate-limits/cursor-desktop-state-db.test.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 46ce53ee-f409-4eea-882c-8fb7cae4561d

📥 Commits

Reviewing files that changed from the base of the PR and between f9940d5 and 9638785.

📒 Files selected for processing (2)
  • src/main/rate-limits/cursor-desktop-state-db.test.ts
  • src/main/rate-limits/cursor-desktop-state-db.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

readCursorDesktopProfile now checks the sibling WAL before opening the database. It returns skipped when the WAL exceeds 32 MiB or its size cannot be read. Missing and non-file WAL paths count as zero bytes. Tests cover these cases, normal database reads, and a missing database.

Priority: ⬆️ High

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 96387

The change skips reading Cursor's desktop login database when its WAL is oversized or cannot be measured. This avoids main-thread freezes. Users whose only login is in an oversized WAL need to run cursor-agent login. No merge-blocking risk remains.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 96387

The change avoids reading oversized or unreadable desktop login data without granting additional access or accepting skipped reads as successful logins. The assessed behavior is narrowly scoped, although the complete pre-change comparison remains limited.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — For the inspected path, the direct consequence of changing WAL size or making its metadata unreadable is loss of that local desktop credential source. Keychain and CLI credentials are evaluated first, and the skipped outcome cannot itself supply credentials or gain authority over Cursor state.

Trust Boundaries and Controls

  • observed — Desktop token and identity extraction is gated on an ok read with a non-empty access token, then routed through sessionFrom and takeLive. The new skipped variant does not bypass this gate or become a live authenticated session.

Resilience and Maintainability Implications

  • inferred — The WAL preflight is a best-effort availability guard, not an atomic size reservation or a hard latency bound: the metadata check and subsequent SQLite open are separate operations, and Cursor can change its files between them. This limitation does not establish a new attack path relative to the prior unguarded read described by the supplied change narrative.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the problem, fix, scope, tradeoffs, linked issue, and test command. However, it does not use the required template and omits or does not explicitly complete several required s… Update the description to follow the repository template. Add the required headings and complete the missing sections, including Visual Proof with N/A and a reason if no UI change exists, Review, Agent skill upstream boundary, Notes, and …
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: skipping oversized Cursor desktop WAL files to prevent main-thread freezes.
Linked Issues check ✅ Passed The PR meets the coding objective in directly linked issue #24360. readCursorDesktopProfile checks state.vscdb-wal before opening state.vscdb and skips WALs larger than 32 MiB. It also skips non…
Out of Scope Changes check ✅ Passed The changed source adds the WAL size probe, skip results, and the related threshold. The added tests verify these behaviors and preserve existing database handling. These changes support the objective…
Full details: Description check

Explanation

The description explains the problem, fix, scope, tradeoffs, linked issue, and test command. However, it does not use the required template and omits or does not explicitly complete several required sections, including Visual Proof with an N/A reason, Review, Agent skill upstream boundary, Notes, and the Checklist items.

Resolution

Update the description to follow the repository template. Add the required headings and complete the missing sections, including Visual Proof with N/A and a reason if no UI change exists, Review, Agent skill upstream boundary, Notes, and the Checklist. Retain the existing technical details under ELI5, What Changed, Why, Linked Issue, and Testing.

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Adds WAL file size check to Cursor IDE profile reader.

The PR appears safe to merge.

Summary

The PR skips the Cursor desktop session read when its WAL exceeds 32 MiB or cannot be inspected, avoiding a potentially long main-thread SQLite operation. Tests cover normal, missing, small-WAL, oversized-WAL, and unreadable-WAL cases.

Reviews (3) · Last reviewed commit: "test(rate-limits): drop the unused datab..."

Comment thread src/main/rate-limits/cursor-desktop-state-db.test.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Minor suggestions only — one doc placement and two small robustness points inline. The mechanism and the 32 MiB cut are sound for the reported scenario.

Reviewed changes

  • WAL size guard — readCursorDesktopProfile now stats state.vscdb-wal and returns an error result before opening when it exceeds CURSOR_DESKTOP_WAL_SKIP_BYTES (32 MiB), avoiding the main-thread wal-index recovery scan that froze the UI (#24360). cursor-auth.ts already drops desktop read errors, so the usage alert is unaffected.
  • New test — cursor-desktop-state-db.test.ts reads a seeded DB, reports a missing DB, and refuses a DB whose WAL is just over the threshold.

I confirmed against sqlite.org that the stall is the single-pass wal-index recovery, that it is linear in -wal bytes, that it runs on the first connector to a quiescent DB (Cursor not running means Orca is first), and that node:sqlite's timeout is only sqlite3_busy_timeout — so it cannot bound this. -wal (not .vscdb) is the right signal for the bounded ItemTable WHERE key IN (…) query, conditional on Cursor's ItemTable.key being uniquely indexed (true in the VS Code lineage). The threshold is a conservative heuristic, not a hard time bound, which is a reasonable call for a guard.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/rate-limits/cursor-desktop-state-db.ts Outdated
Comment thread src/main/rate-limits/cursor-desktop-state-db.ts Outdated
Comment thread src/main/rate-limits/cursor-desktop-state-db.ts Outdated
The sqlite timeout only bounds a lock wait. Replaying a multi-GB WAL
blocked the UI on focus. A normal database still supplies the login.

Fixes stablyai#24360
A stat failure other than a missing file used to look like no WAL, so the
main thread still opened the database. An oversized or unreadable WAL is
now a skip, not a login error, and a small WAL still returns its token.
@innocarpe
innocarpe force-pushed the fix-24360-cursor-wal-skip branch from 8596107 to 9638785 Compare October 1, 2026 11:51
@innocarpe

Copy link
Copy Markdown
Contributor Author

Sync update (9638785a87)

A WAL stat failure other than a missing file no longer looks like an empty WAL, so the database stays unopened. An oversized or unreadable WAL is reported as a skip rather than a login error, and a small WAL-backed database still returns its token.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — minor suggestions inline.

Reviewed changes

  • Fail-closed WAL measurement — cursorDesktopWalBytes now returns null for any statSync error other than ENOENT, and readCursorDesktopProfile returns { status: 'skipped', reason: 'wal-unreadable' } instead of opening the database.
  • Distinct skip result — a new { status: 'skipped'; reason: 'wal-too-large' | 'wal-unreadable' } union member replaces the status: 'error' overload for intentional skips; cursor-auth.ts still only checks status === 'ok', so the intended fall-through is unchanged.
  • Doc placement — the "Reads the Cursor IDE's stored session" JSDoc was moved back onto readCursorDesktopProfile, with a fresh one-liner on cursorDesktopWalBytes.
  • Tests — added a small-WAL read case plus a node:fs mock that makes statSync throw EACCES, asserting the unreadable-WAL skip.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/rate-limits/cursor-desktop-state-db.test.ts Outdated
seedDatabase always writes state.vscdb. The extra parameter had no caller.
@innocarpe

Copy link
Copy Markdown
Contributor Author

Sync update (72eb00055b)

seedDatabase no longer takes a name argument. Every caller writes state.vscdb.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Test-only cleanup — seedDatabase in cursor-desktop-state-db.test.ts no longer takes a name parameter; it now always seeds state.vscdb. This is a pure signature simplification with no production behavior change.
  • Prior feedback — this commit closes the last outstanding Pullfrog nit (unused seedDatabase parameter); the run-1 findings on doc placement, the distinct skipped result, and fail-closed WAL measurement remain addressed.

The delta since the prior review (9638785) is test-only. I re-ran cursor-desktop-state-db.test.ts: 5/5 pass.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@nwparker

nwparker commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Superseded by merged #24572, which credits @innocarpe and moves the desktop SQLite read to a bounded worker so large WALs cannot block the main process. Thank you for the original reproduction and focused fix; #24360 is now closed by the merged continuation.

@nwparker nwparker closed this Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Main process freezes 4–6 s on window focus: Cursor state.vscdb read synchronously on the main thread

2 participants