Skip to content

fix(sentry): unpack better-sqlite3 native chain + skip recoverable groom/oversized-session telemetry#1142

Open
pedramamini wants to merge 1 commit into
mainfrom
fix/sentry-main-native-bindings-groom-noise
Open

fix(sentry): unpack better-sqlite3 native chain + skip recoverable groom/oversized-session telemetry#1142
pedramamini wants to merge 1 commit into
mainfrom
fix/sentry-main-native-bindings-groom-noise

Conversation

@pedramamini

@pedramamini pedramamini commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three field-crash fixes for the stable (main) channel, sourced from Sentry (smash-labs/maestro) and validated against the code + the affected releases (0.17.1 / 0.17.2, channel:stable). Fixes 2 and 3 are byte-identical mirrors of rc PR #1141 so the rc->main merge converges with no conflict; fix 1 is unique to main.

1. Native bindings packaging (escalating on current main)

Sentry: MAESTRO-TE (Cannot find module 'file-uri-to-path', escalating), MAESTRO-Q3 / MAESTRO-JV / MAESTRO-TC / MAESTRO-TD (Could not locate the bindings file). ~40+ events on 0.17.2.

better-sqlite3 -> bindings -> file-uri-to-path, but asarUnpack only listed better-sqlite3 and node-pty:

  • The unpacked bindings.js does require('file-uri-to-path') at load. With file-uri-to-path still inside app.asar, resolution from app.asar.unpacked cannot cross back into the archive -> "Cannot find module 'file-uri-to-path'" (MAESTRO-TE). The require stack confirms it: app.asar.unpacked/.../bindings/bindings.js failing to load a module left in the asar.
  • The mixed packed/unpacked layout also makes bindings compute an in-archive search root for the compiled .node, producing "Could not locate the bindings file. Tried: .../app.asar/.../better_sqlite3.node" (MAESTRO-Q3/JV, via StatsDB.initialize and initCueDb).

Fix: unpack the full native dependency closure so the whole chain resolves consistently from app.asar.unpacked:

"asarUnpack": [
  "node_modules/node-pty/**/*",
  "node_modules/better-sqlite3/**/*",
  "node_modules/bindings/**/*",
  "node_modules/file-uri-to-path/**/*"
]

node-pty needs nothing extra (its only dep, node-addon-api, is build-time headers; it loads its .node directly).

2. Recoverable grooming session loss (MAESTRO-JB, 65 events, stable)

Group-chat context summary spawns a batch agent. If the participant's provider session was deleted mid-summary, the agent emits a recoverable Session not found error (error-patterns.ts session_not_found, recoverable: true) and the code already falls back to a fresh session. The explicit captureException in groupChat.ts reported it anyway. Skip it for that message; real summary failures still report. (Mirrors rc #1141.)

3. Oversized session files (MAESTRO-M9, regressed onto stable)

getGlobalStats reads each session file into a single string; a file too large throws RangeError: Invalid string length. The #1115 carve-out was lost when getGlobalStats was refactored onto statsCache (that refactor reached main, so M9 came back on channel:stable, release 0.17.1). Re-skip the expected RangeError in both the Claude and Codex parse loops in agentSessions.ts, mirroring the storage-layer pattern (claude-/codex-session-storage.ts). (Mirrors rc #1141.)

Out of scope (intentionally not touched)

  • MAESTRO-FM (shared-history write EACCES/EROFS): Sentry shows it is 100% channel:rc (zero stable events). The code is latent on main but does not fire on stable; rc fix(sentry): silence expected-condition telemetry noise on rc #1141 fixes it and it reaches main on the next merge. Not a main field issue.
  • MAESTRO-RA (agent-probe-failed): markFailed already guards with isExpectedConnectionFailure; residual events are genuine signal.
  • MAESTRO-J0 (Failed to load required prompt), MAESTRO-T8/T9 (shellLogs is not iterable): root cause not obvious enough to fix confidently.
  • Native crashes, GLIBC/build-infra (MAESTRO-RS), spawn E2BIG/EINVAL, ENOSPC: already filtered or build/environment issues.

Testing

  • vitest run for agentSessions.test.ts (20) + groupChat.test.ts (54) -> all pass.
  • prettier --check and eslint clean on changed files; type-check shows no errors in changed files.
  • The packaging change is build-config; recommend a packaged smoke build before release to confirm the bindings chain loads.

The added lines in fixes 2 and 3 are verified byte-identical to rc PR #1141.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of oversized session data so affected sessions are skipped more gracefully instead of causing unnecessary errors.
    • Reduced noisy error reporting for expected recovery cases when resetting chat participant context, while still reporting unexpected failures.
    • Expanded app packaging coverage to include additional native dependencies, helping the desktop app start more reliably.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three targeted fixes: agentSessions:getGlobalStats now treats RangeError (oversized files) as an expected skip condition for both Claude and Codex session parsing without Sentry reporting; groupChat:resetParticipantContext suppresses captureException for "Session not found" grooming failures; and package.json adds bindings and file-uri-to-path to asarUnpack.

Changes

Sentry noise reduction for expected errors

Layer / File(s) Summary
RangeError handling in agentSessions stats
src/main/ipc/handlers/agentSessions.ts
Claude and Codex session file parse catch blocks branch on RangeError: oversized files log a "too large to parse" warning and are skipped without Sentry; all other errors still call captureException.
Session not found suppression in groupChat reset
src/main/ipc/handlers/groupChat.ts
groomContext error catch conditionally suppresses captureException when the error message matches /Session not found/i, while still reporting other grooming failures to Sentry.

ASAR Unpack Expansion

Layer / File(s) Summary
asarUnpack dependency globs
package.json
Adds node_modules/bindings/**/* and node_modules/file-uri-to-path/**/* to build.asarUnpack alongside existing native module entries.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • RunMaestro/Maestro#919: Also modifies grooming error handling to suppress Sentry captures for recoverable conditions in context-groomer, directly related to the groupChat grooming error suppression in this PR.

Poem

🐇 Hop, hop, skip the noise!
RangeError files? Too big, rejoice—
No Sentry ping for session gone,
Just log and carry gently on.
The rabbit tidies errors right,
And packs the bindings snug and tight! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: unpacking the native dependency chain and suppressing recoverable Sentry telemetry.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sentry-main-native-bindings-groom-noise

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
package.json (1)

92-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression assertion for the new unpacked dependencies.

src/__tests__/main/stats/integration.test.ts:762-775 currently only checks for node_modules/better-sqlite3/**/*, so this fix can regress silently if bindings or file-uri-to-path get dropped later. Please extend that test to assert these two new asarUnpack entries as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 92 - 94, The unpacked dependency list was
expanded, but the regression test still only asserts the better-sqlite3 entry.
Update the integration test in stats integration to also check for the new
asarUnpack entries for bindings and file-uri-to-path, using the existing
assertion pattern around the unpack list so future drops are caught. Refer to
the stats integration test that validates the unpacked dependency set and extend
the expectations there.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@package.json`:
- Around line 92-94: The unpacked dependency list was expanded, but the
regression test still only asserts the better-sqlite3 entry. Update the
integration test in stats integration to also check for the new asarUnpack
entries for bindings and file-uri-to-path, using the existing assertion pattern
around the unpack list so future drops are caught. Refer to the stats
integration test that validates the unpacked dependency set and extend the
expectations there.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d2a88312-3d91-45fe-af59-9009a8b01230

📥 Commits

Reviewing files that changed from the base of the PR and between d230d0c and 424d7d9.

📒 Files selected for processing (3)
  • package.json
  • src/__tests__/shared/sentryFilters.test.ts
  • src/shared/sentryFilters.ts

@greptile-apps

greptile-apps Bot commented Jun 28, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes two production crash-noise paths. The main changes are:

  • Unpacks bindings and file-uri-to-path with the better-sqlite3 native dependency chain.
  • Drops recoverable context-grooming session-not-found events from Sentry.
  • Adds tests for the new grooming filter and adjacent non-filtered failures.

Confidence Score: 5/5

This looks safe to merge after a small observability cleanup.

  • The packaging change matches the native dependency chain.
  • The grooming filter covers the intended Sentry noise.
  • The filter can also hide a real grooming session-id bug if it is normalized to the same message.

src/shared/sentryFilters.ts

Important Files Changed

Filename Overview
package.json Adds the missing runtime packages in the better-sqlite3 native loading chain to asarUnpack.
src/shared/sentryFilters.ts Adds a grooming session-not-found Sentry drop, but it relies on the normalized message text rather than a recoverability signal.
src/tests/shared/sentryFilters.test.ts Covers the intended dropped grooming messages and verifies timeout and spawn failures still report.

Reviews (1): Last reviewed commit: "fix(sentry): unpack better-sqlite3 nativ..." | Re-trigger Greptile

Comment thread src/shared/sentryFilters.ts Outdated
// a bug we can fix from inside the app. Real grooming failures (timeouts,
// spawn errors, genuine agent crashes) carry different messages and still
// surface.
if (/Grooming error: Session not found/i.test(haystack)) return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Recoverability Is Inferred From Text

When a grooming agent reports any error that the parser normalizes to Session not found, this new filter drops the event solely from the wrapped message. The parser can produce that friendly message from broad session.*not found output, so a real session-id propagation bug during grooming can be hidden from Sentry instead of being reported.

Context Used: CLAUDE.md (source)

…oom/oversized-session telemetry

Three stable-channel (main) field-crash fixes, validated against Sentry
(smash-labs/maestro) on releases 0.17.1/0.17.2 (channel:stable). Fixes 2
and 3 mirror rc PR #1141 exactly so the rc->main merge converges with no
conflict.

1. Native bindings packaging (MAESTRO-TE, MAESTRO-Q3, MAESTRO-JV, plus
   the MAESTRO-TC/TD "Could not locate the bindings file" cluster).
   better-sqlite3 depends on bindings, which depends on file-uri-to-path,
   but asarUnpack only unpacked better-sqlite3 and node-pty. When the
   unpacked bindings.js required file-uri-to-path (still inside app.asar),
   resolution could not cross back into the archive ("Cannot find module
   'file-uri-to-path'"); the mixed packed/unpacked layout also produced
   "Could not locate the bindings file" when bindings computed an
   in-archive search root for the .node. Unpack the full native
   dependency closure (bindings + file-uri-to-path) so the whole chain
   resolves from app.asar.unpacked.

2. Recoverable grooming session loss (MAESTRO-JB, 65 events). Group-chat
   context summary spawns a batch agent; if the participant's provider
   session was deleted mid-summary the agent emits a recoverable "Session
   not found" error (error-patterns.ts session_not_found) and we already
   fall back to a fresh session. Skip captureException for that case in
   groupChat.ts; real summary failures still report.

3. Oversized session files (MAESTRO-M9, regressed onto stable). The
   getGlobalStats parse loops in agentSessions.ts read each session file
   into a single string; a file too large throws "RangeError: Invalid
   string length". The #1115 carve-out was lost in the statsCache
   refactor that reached main. Re-skip the expected RangeError in both
   the Claude and Codex loops, mirroring the storage-layer pattern.
@pedramamini pedramamini force-pushed the fix/sentry-main-native-bindings-groom-noise branch from 424d7d9 to 32d432e Compare June 28, 2026 16:27
@pedramamini pedramamini changed the title fix(sentry): unpack better-sqlite3 native dep chain + drop recoverable groom noise fix(sentry): unpack better-sqlite3 native chain + skip recoverable groom/oversized-session telemetry Jun 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/ipc/handlers/agentSessions.ts`:
- Around line 1002-1014: The oversized-session RangeError path in agentSessions
needs to cache a sentinel result instead of only warning and continuing, because
getGlobalStats will re-read the same file on every refresh. Update the parsing
flow around the session aggregation logic and the file-processing branches in
agentSessions so the expected “too large to parse” case stores a zeroed/sentinel
cache entry keyed by fileMtimeMs, and only retries when the file timestamp
changes; keep the existing non-RangeError failure handling separate from this
special-case cache behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b59f37f9-69f5-4bad-a460-57a37d116fd2

📥 Commits

Reviewing files that changed from the base of the PR and between 424d7d9 and 32d432e.

📒 Files selected for processing (3)
  • package.json
  • src/main/ipc/handlers/agentSessions.ts
  • src/main/ipc/handlers/groupChat.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json

Comment on lines +1002 to +1014
// A session file too large to read into a single V8 string throws
// `RangeError: Invalid string length` (MAESTRO-M9). That's an expected
// boundary for huge sessions, not a bug - skip it and keep aggregating
// the rest. Mirrors the storage-layer carve-out in
// claude-/codex-session-storage.ts.
if (error instanceof RangeError) {
logger.warn(`Claude session file too large to parse: ${file.sessionKey}`, LOG_CONTEXT);
} else {
void captureException(error);
logger.warn(`Failed to parse Claude session: ${file.sessionKey}`, LOG_CONTEXT, {
error,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Cache oversized-session skips instead of retrying them on every stats refresh.

These branches only log and continue. Because Lines 961-968 reprocess any session without a cached entry, the same oversized file will be re-read, re-throw, and re-warn on every agentSessions:getGlobalStats call. Persist a sentinel/zeroed cache entry keyed by fileMtimeMs for the expected “too large” case so it is only retried after the file changes.

Also applies to: 1038-1048

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/ipc/handlers/agentSessions.ts` around lines 1002 - 1014, The
oversized-session RangeError path in agentSessions needs to cache a sentinel
result instead of only warning and continuing, because getGlobalStats will
re-read the same file on every refresh. Update the parsing flow around the
session aggregation logic and the file-processing branches in agentSessions so
the expected “too large to parse” case stores a zeroed/sentinel cache entry
keyed by fileMtimeMs, and only retries when the file timestamp changes; keep the
existing non-RangeError failure handling separate from this special-case cache
behavior.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 32d432e4af

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// report that to Sentry (MAESTRO-JB); only surface unexpected
// grooming failures.
const message = error instanceof Error ? error.message : String(error);
if (!/Session not found/i.test(message)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match Codex missing-session grooming errors

When a Codex group-chat participant's stored thread has been pruned, the session_not_found parser emits Previous Codex session could not be found. Starting fresh conversation. from src/main/parsers/error-patterns.ts:529-531, and groomContext wraps that text before this catch sees it. This regex only drops the literal phrase Session not found, so those recoverable reset failures still call captureException and keep producing the Sentry noise this change is meant to remove.

Useful? React with 👍 / 👎.

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.

1 participant