[BUG] swift-lsp pushes stale 'Cannot find type/module' diagnostics — #17979 fix not extended to SourceKit-LSP
TL;DR
The stale-LSP-diagnostics fix shipped in 2.1.111 (per #17979) does not extend to swift-lsp@claude-plugins-official. SourceKit-LSP continues to push false Cannot find type 'X' in scope and No such module 'Y' after Edit/Write, even on Claude Code 2.1.128. #46651 was a clean repro of this Swift case but auto-closed by the duplicate bot pointing at #17979 (which was only verified for TypeScript).
This re-files the Swift-specific case with multiple fresh repros from a long iOS-migration session, and notes evidence that the same gap likely affects gopls-lsp (one example below).
Environment
- Platform: macOS (Darwin 25.5.0 / 26.4.0 mixed across the session)
- Claude Code: 2.1.128
- Xcode: 26.4.1
- Swift toolchain: 6.3.1 (swift-driver 1.148.6)
- Plugin:
swift-lsp@claude-plugins-official1.0.0 - BSP:
xcode-build-server1.3.0 with validapps/ios/buildServer.json SWIFT_STRICT_CONCURRENCY: complete,SWIFT_VERSION: 6.3- All
xcodebuildinvocations use-resultBundlePath …xcresultper project hook
What's Wrong
<new-diagnostics> arrives within ~100 ms of Edit/Write, before SourceKit-LSP's background indexer has reloaded the affected modules. The push reflects the pre-edit index, which produces three classes of false positives:
- \"Cannot find type 'X' in scope\" — types defined in sibling files within the same module
- \"No such module 'X'\" — top-level imports (
Connect,UIKit,FirebaseAuth) that resolve fine at compile time - \"Main actor-isolated initializer cannot be called from outside\" — when the actor isolation has just been removed in the same edit
In every case, xcodebuild build and xcodebuild test -resultBundlePath … produce ** BUILD SUCCEEDED ** / ** TEST SUCCEEDED ** against the same source state. The diagnostics are pure stale noise.
Concrete repros from one migration session
Repro 1 — fresh file creation
After creating apps/ios/lingram/Data/VocabRepository.swift (Connect-Swift wrapper):
\\\\
VocabRepository.swift:
✘ [Line 29:29] Cannot find type 'Lingram_Vocab_V1_VocabServiceClientInterface' in scope (SourceKit)
✘ [Line 31:22] Cannot find type 'Lingram_Vocab_V1_VocabServiceClientInterface' in scope (SourceKit)
✘ [Line 39:20] Cannot find type 'Lingram_Vocab_V1_CorpusSentence' in scope (SourceKit)
✘ [Line 41:19] Cannot find 'Lingram_Vocab_V1_GetCorpusVocabRequest' in scope (SourceKit)
✘ [Line 46:30] Cannot infer contextual base in reference to member 'transport' (SourceKit)
✘ [Line 49:30] Cannot infer contextual base in reference to member 'missingMessage' (SourceKit)
\\
xcodebuild test -only-testing:lingramTests/VocabRepositoryTests → TEST SUCCEEDED, 3/3 pass. All types resolve correctly. Generated proto types live in apps/ios/lingram/Generated/vocab/v1/vocab.pb.swift and were already committed and indexed.
Repro 2 — class → struct conversion
After changing @MainActor final class VocabRepository → struct VocabRepository: Sendable in the same file:
\\\\
VocabRepositoryTests.swift:
✘ [Line 40:20] Main actor-isolated initializer 'init(client:)' cannot be called from outside of the actor (SourceKit)
✘ [Line 41:33] Value of type 'VocabRepository' has no member 'fetchCorpusVocab' (SourceKit)
✘ [Line 56:20] Main actor-isolated initializer 'init(client:)' cannot be called from outside of the actor (SourceKit)
✘ [Line 57:33] Value of type 'VocabRepository' has no member 'fetchCorpusVocab' (SourceKit)
✘ [Line 71:20] Main actor-isolated initializer 'init(client:)' cannot be called from outside of the actor (SourceKit)
✘ [Line 72:33] Value of type 'VocabRepository' has no member 'fetchCorpusVocab' (SourceKit)
\\
The struct conversion was already in the working tree at the moment of the diagnostic push. xcodebuild test passed against the new struct shape. The diagnostics are reading the pre-edit @MainActor final class index.
Repro 3 — Swift toolchain version bump
After bumping SWIFT_VERSION: \"6.0\" → \"6.3\" in project.yml and running xcodegen generate:
\\\\
VocabRepositoryTests.swift:
✘ [Line 1:8] No such module 'Connect' (SourceKit)
VocabRepository.swift:
✘ [Line 1:8] No such module 'Connect' (SourceKit)
\\
xcodebuild build → BUILD SUCCEEDED. Connect package was resolved by SwiftPM and lives in apps/ios/build/derived/SourcePackages/checkouts/connect-swift/. The LSP didn't reload the BSP context after the version change.
These three repros surfaced inside a single multi-hour migration session. Every <new-diagnostics> push following an Edit/Write of any non-trivial Swift file was either fully or partially stale.
Adjacent gopls evidence
In the same session, after Edit-ing a Go test file that referenced symbols just defined in a sibling file:
\\\\
pgx_vocab_test.go:
(gopls) <claims symbols undefined that go build resolves cleanly>
\\
go build ./... and go test ./... both clean. This is the same pattern as #50271 (pyright cross-module) — suggesting #17979's fix did not generalize beyond the TypeScript case it was verified against.
Why #46651 should reopen / why this is filed fresh
The dup-detector bot closed #46651 against #17979 based on text similarity, not on whether the 2.1.111 fix actually extended to swift-lsp. It did not. swift-lsp@claude-plugins-official 1.0.0 is a 26-line README plugin with zero configuration surface — it does not expose the synchronization behavior introduced in 2.1.111 to SourceKit-LSP's lifecycle. After 7-day auto-lock, comments cannot reopen #46651, so this filing is the only path back to a tracked tickets.
What Should Happen
Per #17979's own resolution path, the fix is: wait for the LSP server to settle before injecting <new-diagnostics>. SourceKit-LSP exposes the necessary hooks already:
workspace/synchronize—{ index: true }blocks until background indexing completesworkspace/triggerReindex— manual reindex triggersourceKit/_isIndexing— query indexing state
The 2.1.111 fix presumably calls the equivalent of workspace/synchronize (or polls until idle) for TypeScript before publishing diagnostics. The same wait should apply to swift-lsp. If the wait already runs but is bypassed for plugin-loaded LSP servers, that's the gap.
Acceptance
After the fix, in this same lingram repo:
- Create a new Swift file referencing types from
apps/ios/lingram/Generated/vocab/v1/ - Save the file
- The
<new-diagnostics>push following the save should report 0 false positives matchingCannot find type … in scopefor those types xcodebuild buildagainst the same source state continues to return** BUILD SUCCEEDED **
Related
- #17979 — parent (closed; fixed in 2.1.111 for TypeScript)
- #46651 — Swift case auto-closed as duplicate of #17979, locked
- #44722 — Swift iOS-only SPM platform context (different but adjacent)
- #50271 — pyright cross-module after git ops (parallel pattern; suggests fix is per-LSP not generic)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗