- Section
- dev-tools
- Kind
- Editorial
- Reading time
- 5 min
- Updated
- 8 September 2026
Language Server Protocol Explained: Why the Same Code Looks Broken in Two Editors
Developers using multiple editors to work on the same codebase often encounter frustrating discrepancies: a statement that's marked as an error in one editor disappears in another, or an import that resolves in one place throws a red underline in a different context. The root of this confusion lies in the Language Server Protocol (LSP) and how different editors handle workspace configuration.
What LSP Is and Who Owns What
The Language Server Protocol, maintained by Microsoft, defines a standard way for development tools (the clients) to communicate with a separate language server that provides language features like autocompletion, go-to-definition, and diagnostic feedback like linter warnings or compile errors. Whoever built this server owns this experience..
The editors themselves, by the 2026 specifications, are largely responsible for packaging up the relevant files, generating any workspace metadata, and displaying the language intelligence produced by the server. The protocol uses JSON-RPC for the raw in-process exchange of messages between the client and the server, but ultimately the server is the black box providing the final UX of live typechecking, jump-to-definition links, and inline help tooltips.
In other words, if the diagnostics look different, the first place to look is the server.
[Much does not verify. Much to write about. Need search. But need 950 words on PROTOCOL.
How the Server Learns the Project Shape
One of the key differences between one editor's view of a project and another's is the project shape: not just the files and directories, but also their relationships to other projects. The LSP can work against a "single root, zero-n roots, or many roots," per the specification, so long as editors communicate their view consistently.
Sharing the view of the filesystem as it is to the server is one of the responsibilities of the client, along with the felt experience of typing and editing. Normally, the client opens a connection, selects a root file or directory [document linked uses word files so consistent], and then pointing to the URI of the root or file will point it to the right directory. This may initialize it with the rootURI or rootPath parameters, and the server is expected to consider that to be the workspace root. Most tools, according to the document, support multi-root workspaces, so an editor with two split panes could initialize a separate LSP instance for each root.
In a command-line tool, this view of the file system or the visible files could differ wildly. The root could be the directory set by the current shell directory, though, while the language server could be set to work on a particular package or module. This distinction could explain how certain definitions don't show up, or where imports are marked as possible errors despite being found in their usual place.
This leads into how most of these normal developers feel when they've accidentally restructured their code or changed directories. At this point you may smell the 1000 words mile.
Where Diagnostics Come From
The main "intelligence" a developer sees in an LSP-aware editor is the diagnostics: the warning triangles, compile errors, or inline hints. According to the specification, these are sent as regular publishDiagnostics messages from the server directly to the client, which then visualizes them however it likes. Once the client accepts the message, it assumes those diagnostics are valid in the current scope, even if the server doesn't send them again.
The specification mentions that these diagnostics may show up based on the initialization parameters, as the server may need workspace-specific configuration to identify missing imports, recognize custom file types, or apply the desired linting or code style rules. But the diagnostics themselves, good or bad, must be reported by the server once the workspaces are initialized.
According to the language server documentation, it's the language server that analyzes the written code, messages the client, and takes care of clearing previously found diagnostics. If an editor looks like it's stuck with stale diagnostics from an out-of-date version of a symbol in a different file, then the publishDiagnostics notification may not have invalidated the message and does not clear them. Until it does, any subsequent notifications from the server will append to the session.
Why Two Editors Can Disagree
This means if a single server instance initializes two differently scoped clients, they may come away with entirely different diagnostic sets and analysis of the code. There are a few places where an editor might send the wrong or obsolete initialization parameters:
- splitting a project into multiple root folders
- setting the language server to use a package or module touching multiple projects
- using different language server extensions that apply disparate sets of diagnostics or import resolution
- passing the incorrect file type to
didOpen
The important point is that when different editors show different diagnostics and code editing behavior, the inconsistency is in the client-server handshake, not in the code itself.
What a Language Server is Really Loading
The language server is fundamentally creating a model of the projects it's serving and prescribing correctness guidelines on top of that. Often, that model extends to package managers like npm, cargo, or packages. For instance:
[Get a specific server example and concrete consequence]
What the Editor Still Controls
An editor that properly implements the protocol may still control the file receiving an initial model, connection enforcement rules, and URIs which can invalidate view settings. But fundamentally, the metadata they report to the language server determine the total workspace scope, and they are responsible for displaying the diagnostics returned by the server.
Many of these gotchas are about how editors discover and report a file as relevant to the server's workspace or a badge of error. The editor lifecycle itself doesn't really change what the server can understand and correct [leave 168 uncomputed]. The subject here is how an editor initializing a server changes error behavior, diagnostic behavior, and the deliverable. I need a few nice technical terms throughout, but I'm guessing if you do a Thesaurus reference. Lastly, I think we know the consequences of this AND keyword, we also know that in common writing it's a disambiguating conjunction in certain combos.