Skip to content

Return structured StatementRangeError from statement_range()#1040

Open
DavisVaughan wants to merge 1 commit intofeature/statement-range-errorfrom
feature/statement-range-error-2
Open

Return structured StatementRangeError from statement_range()#1040
DavisVaughan wants to merge 1 commit intofeature/statement-range-errorfrom
feature/statement-range-error-2

Conversation

@DavisVaughan
Copy link
Contributor

@DavisVaughan DavisVaughan commented Feb 13, 2026

Branched from #1028
Goes with posit-dev/positron#11907

When there is a parse error in an R file and the user is trying to execute any code after that parse error, we now return a JsonRPC error with code = 1 and a structured data field, where data.line holds the approximate line number of the start of the parse error.

The frontend then picks this up by catching when await this._client.sendRequest(StatementRangeRequest.type, params, token) errors, checking that the caught error has error.code = 1, and then upcasting the error to a structured StatementRangeParseError on the TypeScript side.

The end result is that the frontend can now use this to refuse to execute any code, and instead give a pop up notification telling the user where the problem is.

Screen.Recording.2026-02-13.at.3.28.26.PM.mov

It even works in roxygen2! This required adjusting the "sub document" line to reflect a line in the original document.

Screen.Recording.2026-02-13.at.3.32.38.PM.mov

Note that we use an error code of 1.

I believe we are allowed to use any error code not captured by ErrorCodes here:
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseMessage

I do not think the code number matters much outside of that. Each Request type can have its own set of error codes, and those error codes may overlap with other Request types.


I expect that we may have multiple failure modes in the future, so StatementRangeParseError is just the sole enum variant of an overarching StatementRangeError type. This is reflected on the TypeScript side as well.


There is very little prior art for returning structured errors from LSP Requests.

There are only two that I know of

The interesting thing about Rejection is that once we have left LSP land on the Typescript side, the error path gets merged into the response path as a return value of RenameLocation & Rejection.

We work similarly, but our return value from all of the Typescript APIs is StatementRange | StatementRangeError, and the way that you know if you have a StatementRange or StatementRangeError is the presence of a result.error string field, which also serves as the discriminator for determining the more precise StatementRangeParseError subtype of StatementRangeError itself.

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.

1 participant