Skip to content

Always pull diagnostics on didOpen even if document is already known via tab#1719

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/fix-text-document-diagnostics
Draft

Always pull diagnostics on didOpen even if document is already known via tab#1719
Copilot wants to merge 2 commits intomainfrom
copilot/fix-text-document-diagnostics

Conversation

Copy link

Copilot AI commented Feb 6, 2026

When tabs are restored (e.g. hot exit, restart), tab events fire before textDocument/didOpen. The tab handler triggers a diagnostic pull with disk content, then the didOpen handler's knows() check skips re-pulling—so diagnostics are never recomputed with the actual document content (which may include unsaved changes).

  • Remove the knows() early-return guard in the didOpen handler so it always triggers a diagnostic pull
  • pullAsync already handles concurrent requests correctly: if a pull is in-flight, it cancels and reschedules with current content
// Before: skipped pull if document was already known via tab
if (this.diagnosticRequestor.knows(PullState.document, textDocument)) {
    return;
}

// After: always pull on didOpen
if (matches(textDocument)) {
    this.diagnosticRequestor.pull(textDocument, () => { addToBackgroundIfNeeded(textDocument); });
}
Original prompt

This section details on the original issue you should resolve

<issue_title>Client requests textDocument/diagnostics before textDocument/didOpen</issue_title>
<issue_description>I don’t know how to reproduce this reliably in a fresh repo, but it’s happening every time I restart the language client/server in my window right now. In the logs, you can see two textDocument/didOpen, followed by textDocument/diagnostic for file:///Users/andrew/Developer/microsoft/typescript-go/Herebyfile.mjs, which is not one of the two that's been already opened. The textDocument/didOpen for Herebyfile.mjs comes later (very end of the logs pasted), and after that, there’s no subsequent textDocument/diagnostic request for it. This must be a bug, because I have unsaved changes in that file's editor, so the didOpen content is going to be different from the text on disk, which is the only thing we could access in order to compute diagnostics.

This actually causes us (TypeScript) to return an error, because from observation we counted on the client only asking for diagnostics for files it’s already opened. But even if we gracefully served the request, the diagnostics shown would be for the wrong content.

2026-02-05 14:51:37.763 [trace] Sending request 'shutdown - (11)'.
2026-02-05 14:51:37.764 [trace] Received response 'shutdown - (11)' in 1ms.
No result returned.
2026-02-05 14:51:37.764 [trace] Sending notification 'exit'.
No parameters provided.
2026-02-05 14:51:37.764 [trace] Received notification 'window/logMessage'.
Params: {
    "type": 3,
    "message": "handled method 'shutdown' (11) in 11.333µs"
}
2026-02-05 14:51:37.766 [trace] Sending request 'initialize - (0)'.
Params: {

}
2026-02-05 14:51:37.775 [trace] Sending notification 'initialized'.
Params: { (removed for brevity) }
2026-02-05 14:51:37.776 [trace] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/path.ts",
        "languageId": "typescript",
        "version": 59,
        "text": "import { Path } from \"@typescript/ast\";\r\n\r\nconst ..."
    }
}
2026-02-05 14:51:37.776 [trace] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/node.ts",
        "languageId": "typescript",
        "version": 44,
        "text": "import {\r\n    type Node,\r\n    type NodeArray,\r\n    type SourceFile,\r\n    ..."
    }
}
2026-02-05 14:51:37.776 [trace] Sending request 'textDocument/diagnostic - (1)'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/Herebyfile.mjs"
    }
}
2026-02-05 14:51:37.776 [trace] Sending request 'textDocument/diagnostic - (2)'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/path.ts"
    }
}
2026-02-05 14:51:37.776 [trace] Sending request 'textDocument/diagnostic - (3)'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/node.ts"
    }
}
2026-02-05 14:51:37.776 [trace] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/async/api.ts",
        "languageId": "typescript",
        "version": 19,
        "text": "/// <reference path=\"../node.ts\" preserve=\"true\" / ..."
    }
}
2026-02-05 14:51:37.777 [trace] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/base/api.ts",
        "languageId": "typescript",
        "version": 12,
        "text": "/**\r\n *  ..."
    }
}
2026-02-05 14:51:37.777 [trace] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/_packages/api/src/proto.ts",
        "languageId": "typescript",
        "version": 2,
        "text": "export interface ConfigResponse {..."
    }
}
2026-02-05 14:51:37.778 [trace] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///Users/andrew/Developer/microsoft/typescript-go/Herebyfile.mjs",
        "languageId": "javascript",
        "version": 112,
        "text": "// @ts-check\r\n\r\nimport AdmZip from \"adm-zip\";\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n..."
    }
}
```</issue_description>

<agent_instructions>Can you do an analysis of the issue and propose a possible code change that fixes it.</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@dbaeumer</author><body>
I investigated and here is what I think is happening:

- due to the code here in the TypeScript-Go extension : https://github.com/microsoft/typescript-go/bl...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/vscode-languageserver-node#1718

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

… tab

When a document is restored from a tab (e.g., hot exit), the tab open
event fires before the didOpen notification. The tab handler triggers a
diagnostic pull with potentially stale content. Previously, when didOpen
fired, the knows() check would skip re-pulling diagnostics.

Now the didOpen handler always triggers a diagnostic pull. The existing
pullAsync logic handles deduplication - if a request is already active,
it cancels it and reschedules with the current document content.

Fixes #1558

Co-authored-by: dbaeumer <1931590+dbaeumer@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix client requests for diagnostics before didOpen Always pull diagnostics on didOpen even if document is already known via tab Feb 6, 2026
Copilot AI requested a review from dbaeumer February 6, 2026 13:46
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.

2 participants