ADFA-4755: stop reporting benign stale-classpath failures from Kotlin LSP indexer#1550
ADFA-4755: stop reporting benign stale-classpath failures from Kotlin LSP indexer#1550hal-eisen-adfa wants to merge 3 commits into
Conversation
…SP indexer GlitchTip issue CODEONTHEGO-D is our own telemetry, not a crash. During source-file indexing, FIR resolution tried to read a dependency jar that no longer existed on disk - a Gradle transform-cache entry evicted or rebuilt while indexing was in flight - and threw NoSuchFileException wrapped in KotlinIllegalArgumentExceptionWithAttachments. analyzeDeclaration already caught it and reported it via Sentry.captureException (userCount: 0). The condition is benign and transient: the next index pass, once the build settles, succeeds. - Add Throwable.isMissingClasspathFile(): walks the cause chain for NoSuchFileException / FileNotFoundException (bounded against self-cause). - analyzeDeclaration: skip Sentry reporting for these (debug-log instead), so we stop emitting this noise. - indexSourceFile: wrap the analysis block in the module's standard degrade guard (rethrow CancellationException; report+skip otherwise). A setup-time escape - outside the per-declaration runCatching - would otherwise reach KtSymbolIndex.scope, which has no CoroutineExceptionHandler, and crash the app (the hazard OrganizeImportsAction already documents). Adds predicate unit tests. Most of the file diff is a mandatory Spotless full-file reformat triggered by the origin/stage ratchet; see `git diff -w` for the behavioral change.
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
|
Warning Review limit reached
Next review available in: 34 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughSource indexing now detects missing classpath files, skips transient failures, reports other analysis errors, preserves cancellation, and adds tests for nested exception handling. Symbol-analysis construction is reformatted without changing field mappings. ChangesClasspath-aware source indexing
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant SourceFileIndexer
participant AnalysisSession
participant Logger
participant Sentry
SourceFileIndexer->>AnalysisSession: extract symbols
AnalysisSession-->>SourceFileIndexer: analysis failure
SourceFileIndexer->>SourceFileIndexer: inspect cause chain
SourceFileIndexer->>Logger: debug-log missing classpath failure
SourceFileIndexer->>Sentry: report other analysis failure
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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
`@lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexer.kt`:
- Around line 187-191: Update the onFailure handler around the runCatching call
in SourceFileIndexer to detect CancellationException and immediately rethrow it
before handling missing classpath files or reporting failures. Preserve the
existing isMissingClasspathFile handling for all other errors.
- Around line 158-166: In the exception handler surrounding the indexing
operation in SourceFileIndexer, replace the broad Throwable catch with handling
for the expected recoverable exception types, such as RuntimeException from FIR
wrappers and IOException for missing classpath files. Preserve the existing
isMissingClasspathFile branching, logging, Sentry capture, and return behavior,
while allowing fatal JVM errors such as OutOfMemoryError and StackOverflowError
to propagate.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1cf7dd0d-230d-4bbd-9861-6eca7e3be89e
📒 Files selected for processing (2)
lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexer.ktlsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexerTest.kt
Preempts a review suggestion to narrow the catch: this scope has no CoroutineExceptionHandler, so narrowing to Runtime/IOException would let Error-type failures (StackOverflowError, LinkageError) crash the app instead of degrading. No behavior change.
…nCatching runCatching catches Throwable, so a cancellation during symbol analysis would be swallowed and mis-reported to Sentry instead of aborting. Rethrow it first, matching the module's other analysis handlers. Addresses CodeRabbit review.
Code review (Claude Code, xhigh)Scope: Verdict: The core fix is sound — it catches the real crash origin ( Correctness1. Per-declaration missing-jar skip commits a partial index marked 2. Wrapped cancellation is misrouted to Sentry-as-error and swallowed (asymmetric depth). 3. Session-setup skip leaves the index inconsistent after 4. A rebuilt (truncated) jar throws 5. Persistent (non-transient) missing-classpath is indistinguishable from transient and swallowed at debug forever. 6. The cause walk covers Altitude / fix depth7. This is a per-call-site catch, not a scope-level backstop — sibling paths on the same handler-less scope still crash. Test coverage8. The crash-fix control flow itself is untested. 9. No test that 10. The pure-predicate tests carry the heavy Cleanup (low)11. New module logger uses a hardcoded FQN string. 12. The rethrow-cancellation -> Automated review via Claude Code ( |
Summary
Fixes ADFA-4755 / GlitchTip CODEONTHEGO-D (
KotlinIllegalArgumentExceptionWithAttachments: Error while resolving ... from RAW_FIR to TYPES).This issue is not a crash — it's our own telemetry.
SourceFileIndexer.analyzeDeclarationalready wraps per-declaration analysis inrunCatching { ... }.onFailure { Sentry.captureException(err) }. The observed stack originates inanalyzeProperty → KaPropertySymbol.returnType, inside thatrunCatching, so the exception is caught, the symbol skipped, and indexing continues (userCount: 0). TheSentry.captureExceptioncall — which forwards the FIRKotlinExceptionWithAttachmentsattachments — is exactly what emits the GlitchTip event.Root cause is benign and transient: FIR resolution tried to read a dependency jar (
.../.gradle/caches/8.14.3/transforms/.../lifecycle-viewmodel-2.5.1/jars/classes.jar) that no longer existed — a Gradle transform-cache entry evicted or rebuilt while indexing was in flight. The next index pass, after the build settles, succeeds. Reporting it as an error is noise.Changes
Throwable.isMissingClasspathFile()— walks the cause chain (bounded against a self-referential cause) forNoSuchFileException/FileNotFoundException.analyzeDeclaration— skipSentry.captureExceptionfor these; debug-log instead. Kills the GlitchTip noise.indexSourceFile— wrap the analysis block in the module's standard degrade guard (rethrowCancellationException; log + report + skip otherwise). Defense in depth: a setup-time escape — outside the per-declarationrunCatching— would otherwise propagate intoKtSymbolIndex.scope, which has noCoroutineExceptionHandler, and crash the app. This is the exact hazardOrganizeImportsActionalready documents.Testing
:lsp:kotlin:testV8DebugUnitTest --tests "...SourceFileIndexerTest"— 8/8 pass (5 newisMissingClasspathFilepredicate tests: direct, wrapped, deeply nested,FileNotFoundException, and negative cases; plus the 3 pre-existing indexer tests).:app:assembleV8Debug— builds.The live condition (a cache jar vanishing mid-index) isn't deterministically reproducible on device; correctness rests on the predicate tests plus the guard matching the module's established degrade pattern (
KotlinDiagnosticProvider,KotlinCompletions).Reviewer note
Most of the file diff is a mandatory Spotless full-file reformat the
origin/stageratchet triggers once the file is touched (grandfathered param/expression wrapping, trailing commas). Review the behavioral change withgit diff -w.Out of scope
Making the Kotlin analysis classpath resilient to transform-cache churn (re-resolving vanished jars) is a much larger change; this PR silences the benign telemetry and removes the crash risk.