Skip to content

vscode/lsp type casting bug #5630

Description

@TUdby

I installed the lsp and the vscode extension (awesome, love them), and it's adding type casting in my select statement. This is great, no complaints on the design philosophy there, but it's getting caught up when I try changing a column name, and even in the middle of when I'm still typing a new column name. It renders the type cast inside of the my column name.

The problem is fixed when I render the model, or close and open the file again, so nothing is getting broken, but it's inconvenient when I'm trying to write a model. Here's an example using the quickstart project. I added a column named 'big_boy_column' and you can see the type cast getting stuck in the middle of that.

Image

Activity

  1. tripleaceme commented on Sep 24, 2026

    @tripleaceme
    Contributor

    I'd like to take this one if it's free — unassigned with no linked PR right now.

    Reproducing first, since the report is precise about the trigger: the cast renders inside the column name while the name is still being typed, and it clears on re-render or on reopening the file. That reads like the inlay hints are positioned from a stale document version — the hint keeps an offset computed before the edit, so it lands mid-token once the text has shifted underneath it.

    What I plan to check, in order:

    1. whether the hint response carries the document version it was computed against, and whether that is compared against the current one before the hints are applied
    2. whether hints are being requested and applied while the document is still changing, rather than being invalidated on edit and recomputed
    3. whether this is debounce-only, in which case the fix is to drop responses that no longer match the document version rather than to wait longer

    I'll come back with what actually causes it before changing anything. If it turns out to be on the server side in sqlmesh/lsp rather than in the extension, I'll say so rather than quietly widening the scope.

  2. tripleaceme commented on Sep 24, 2026

    @tripleaceme
    Contributor

    Reproduced, and the cause is not what I guessed above — posting the correction since I got the mechanism wrong in public.

    It is not a document-version problem, a race, or debouncing. All three of the things I said I'd check are dead ends. sqlmesh/lsp/main.py registers did_open and did_save and no textDocument/didChange handler, so the server's parsed model is frozen until you save. sqlmesh/lsp/hints.py::get_hints derives every hint's character from sqlglot token metadata on lsp_context.context.get_model(...).query — the model parsed from disk when the context was last loaded.

    VS Code invalidates and re-requests inlay hints on every change, so it is asking correctly; the server answers with offsets from the last saved parse. Version-stamping the responses would not have helped: the server has no correct answer to give at any version, it would just withhold a wrong one.

    Direct reproduction — a temp project, edit the buffer, call get_hints:

    saved buffer:   1 AS big_boy              hint at character 14
    edited buffer:  1 AS big_boy_column       server still returns character 14
    VS Code renders: 1 AS big_boy::INT_column
    

    Which is the screenshot in the issue.

    Two other things worth recording:

    • The extension has no inlay-hint code at all — a plain LanguageClient with stock vscode-languageclient, no middleware. There is nothing to fix on the TypeScript side, which is where I would have looked first.
    • A second symptom falls out of the same cause: inserting a line above shifts all the text but not the hints, so they attach to the wrong columns with the wrong types. Not reported, same fix.

    PR up shortly. It passes the live document text into get_hints and takes positions from parsing that, while still resolving types by name against the loaded model.

    One thing you may want to weigh in on, since it is a UX call rather than a correctness one: while a column is being renamed it now has no hint until the next save, instead of a hint inside the word. I think that is the better of the two, but the alternative is holding the last good hint and suppressing only the ones that would split a token.

    Also, and out of scope here: diagnostics are published from the same reload-on-save context, so they are likely stale between saves in the same way. I have not looked into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions