You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
prepareRename response { defaultBehavior: true } is treated the same as null #1749
The LSP 3.17 spec defines distinct semantics for null vs { defaultBehavior: true } from textDocument/prepareRename:
If { defaultBehavior: boolean } is returned (since 3.16) the rename position is valid and the client should use its default behavior to compute the rename range. If null is returned then it is deemed that a textDocument/rename request is not valid at the given position.
From what I can tell, the current implementation of textDocument/prepareRename packaged in the method client.renameProvider() which treats both null and { defaultBehavior: true } as the same case (i.e., the rename position is invalid which skips textDocument/rename requests from being sent).
Tip
For the time being, I got around the unexpected behavior of { defaultBehavior: true } being treated as null by returning the range and placeholder values passed into textDocument/prepareRename
To make the use case of { defaultBehavior: true } consistent across language-clients, textDocument/prepareRename should be able to determine this case is a valid rename position for clients who use the vscode-languageclient package
} else if (this.isDefaultBehavior(result)) {
- return result.defaultBehavior === true ? null : Promise.reject(new Error(`The element can't be renamed.`))+ return result.defaultBehavior === true ? result : Promise.reject(new Error(`The element can't be renamed.`))
}
I submitted #1748 to reflect this change + I added some new tests for verifing the behavior of textDocument/prepareRename the /client & /client-node-tests for the new rename related features.
Although, I should probably mention that I don't normally use a language client that provides its own defaultBehavior rename provider (neovim user), so maybe the confusion I've encountered and my purposed fix isn't needed here. In which case, I still think it might be beneficial to allow more distinction between defaultBehavior: true vs null prepareRename request responses
Happy to make any adjustments to the PR if needed, just let me know!
Thanks for all the work y'all maintainers have put into this project over the years! It's amazing
I looked at the current implementation and the VS Code API treats null different than the LSP spec. The VS Code API for prepare rename says:
/**
* Optional function for resolving and validating a position *before* running rename. The result can
* be a range or a range and a placeholder text. The placeholder text should be the identifier of the symbol
* which is being renamed - when omitted the text in the returned range is used.
*
* *Note:* This function should throw an error or return a rejected thenable when the provided location
* doesn't allow for a rename.
*
* @param document The document in which rename will be invoked.
* @param position The position at which rename will be invoked.
* @param token A cancellation token.
* @returns The range or range and placeholder text of the identifier that is to be renamed. The lack of a result can signaled by returning `undefined` or `null`.
*/
So returning null tells VS Code the lack of a result and therefore forces its default behavior.
If the server returns null it will be converted to a rejected promise here: return Promise.reject(new Error(The element can't be renamed.));
Not sure if what I think would be classified as incorrect. My primary reason for opening this issue was for visibility that could be helpful to other language-clients tracking this repo.
Coming from text editors that don't have a default behavior for renaming identifiers (I use vim/nvim so :%s/old_name/new_name/g is used for regex matching renaming), my expectation for what a default behavior response from textDocument/prepareRename was basically that textDocument/prepareRename didn't calculate any ranges and was implying textDocument/rename should calculate the rename locations. Is default behavior in vscode using the grammar from LANG.tmLanguage.json to find identifiers, or is the defaultBehavior the server textDocument/rename?
In my case, I was just looking to use prepareRename for filtering bad rename locations, but had trouble figuring out how to indicate the rename location was good. Using the equivalent Range in textDocument/prepareRename result that matches the symbol inside the Location param of this request seems to not have any issues for me. This doesn't use the prepareRename default behavior provider for the range right?
I still find it a little unclear what happens when a textDocument/prepareRename returns a Range that deviated from the Position param, does that ever effect the position textDocument/rename receives in its params, or is it used for the client default behavior identifier?
Possibly, it might be worth adding more documentation to defaultBehavior in the spec so that developers of language clients or text-editors that support lsp avoid possibly interpreting its usage incorrectly.
Activity
dbaeumer commentedon May 19, 2026
I looked at the current implementation and the VS Code API treats
nulldifferent than the LSP spec. The VS Code API for prepare rename says:So returning
nulltells VS Code the lack of a result and therefore forces its default behavior.If the server returns
nullit will be converted to a rejected promise here:return Promise.reject(new Error(The element can't be renamed.));Can you explain why you think this is incorrect.
ndonfris commentedon Jun 11, 2026
Not sure if what I think would be classified as incorrect. My primary reason for opening this issue was for visibility that could be helpful to other language-clients tracking this repo.
Coming from text editors that don't have a default behavior for renaming identifiers (I use vim/nvim so
:%s/old_name/new_name/gis used for regex matching renaming), my expectation for what a default behavior response fromtextDocument/prepareRenamewas basically thattextDocument/prepareRenamedidn't calculate any ranges and was implyingtextDocument/renameshould calculate the rename locations. Is default behavior in vscode using the grammar fromLANG.tmLanguage.jsonto find identifiers, or is the defaultBehavior the servertextDocument/rename?In my case, I was just looking to use prepareRename for filtering bad rename locations, but had trouble figuring out how to indicate the rename location was good. Using the equivalent
RangeintextDocument/prepareRenameresult that matches the symbol inside theLocationparam of this request seems to not have any issues for me. This doesn't use the prepareRename default behavior provider for the range right?I still find it a little unclear what happens when a
textDocument/prepareRenamereturns aRangethat deviated from thePositionparam, does that ever effect the positiontextDocument/renamereceives in its params, or is it used for the client default behavior identifier?Possibly, it might be worth adding more documentation to
defaultBehaviorin the spec so that developers of language clients or text-editors that support lsp avoid possibly interpreting its usage incorrectly.