Skip to content

[flutter_tools] Compute LSP Content-Length header using UTF-8 byte length - #191377

Merged
auto-submit[bot] merged 1 commit into
flutter:masterfrom
bkonyi:issue-191309
Aug 20, 2026
Merged

auto-submit[bot] merged 1 commit into
flutter:masterfrom
bkonyi:issue-191309

Conversation

@bkonyi

@bkonyi bkonyi commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes flutter analyze crashing with FormatException: Unexpected end of input when analyzing a project whose path contains non-ASCII characters (e.g. Alexander’s MacBook Pro with right single quotation mark ’ / U+2019).

In AnalysisServer._writeMessage, the Content-Length header was being calculated using message.length (UTF-16 code units) rather than the UTF-8 encoded byte length required by the LSP specification. When messages contained multibyte Unicode characters (such as in rootUri or workspaceFolders), the header under-reported the payload length, causing the analysis server's JSON parser to receive a truncated payload and exit prematurely with code 255.

Also updates MockLspServerProcess to parse stdin as a stream of raw bytes and compute outgoing message length in bytes to faithfully simulate the LSP transport layer.

Related Issues

Fixes #191309

Tests

  • Added AnalysisServer handles non-ASCII project path unit test in packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart.

Pre-launch Checklist

…ngth

Fixes an issue where `flutter analyze` crashes with a `FormatException: Unexpected end of input` when analyzing projects whose path contains non-ASCII characters.

In `AnalysisServer._writeMessage`, the `Content-Length` header was being calculated using `message.length` (UTF-16 code units) rather than the UTF-8 encoded byte length required by the LSP specification. When messages contained multibyte Unicode characters (such as in `rootUri` or `workspaceFolders`), the header under-reported the payload length, causing the analysis server's JSON parser to receive a truncated payload and exit prematurely.

Also updates `MockLspServerProcess` to parse stdin as a stream of raw bytes and measure outgoing message length in bytes to faithfully simulate the LSP transport layer.

Fixes flutter#191309
@github-actions github-actions Bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Aug 19, 2026
@bkonyi
bkonyi requested a review from DanTup August 19, 2026 22:48
@bkonyi
bkonyi marked this pull request as ready for review August 19, 2026 22:48
@bkonyi bkonyi added the CICD Run CI/CD label Aug 19, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the AnalysisServer and its mock implementation to calculate and handle LSP message lengths in bytes rather than string characters, resolving issues with non-ASCII characters in project paths. A new test case is also added to verify this behavior. The review feedback suggests optimizing the message writing in both production and mock code to avoid encoding the message string multiple times by writing the pre-encoded bytes directly.

Comment on lines +147 to +148
final List<int> encodedMessage = utf8.encode(message);
_process?.stdin.write('Content-Length: ${encodedMessage.length}\r\n\r\n$message');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid encoding the potentially large message string twice (once to calculate the byte length with utf8.encode, and a second time implicitly when writing the string to _process?.stdin), you can write the header and the pre-encoded message bytes directly to stdin using add.

    final List<int> encodedMessage = utf8.encode(message);
    _process?.stdin.add(utf8.encode('Content-Length: ${encodedMessage.length}\r\n\r\n'));
    _process?.stdin.add(encodedMessage);

Comment on lines +182 to +183
final List<int> bytes = utf8.encode(message);
_stdoutController.add(utf8.encode('Content-Length: ${bytes.length}\r\n\r\n$message'));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the production code, we can avoid encoding the message string twice here by combining the encoded header and the pre-encoded message bytes before adding them to the stream controller.

Suggested change
final List<int> bytes = utf8.encode(message);
_stdoutController.add(utf8.encode('Content-Length: ${bytes.length}\r\n\r\n$message'));
final List<int> bytes = utf8.encode(message);
_stdoutController.add(<int>[
...utf8.encode('Content-Length: ${bytes.length}\r\n\r\n'),
...bytes,
]);

@DanTup DanTup left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

It'd be nice if we could reuse the classes from the server here (probably by moving them into a publishable package - which we've previously discussed doing to share the generated types) to avoid having multiple copies that might be slightly different.

https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server/lib/src/lsp/lsp_packet_transformer.dart#L29

@bkonyi

bkonyi commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

lgtm!

It'd be nice if we could reuse the classes from the server here (probably by moving them into a publishable package - which we've previously discussed doing to share the generated types) to avoid having multiple copies that might be slightly different.

https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server/lib/src/lsp/lsp_packet_transformer.dart#L29

I agree! It'd be great to have a shared implementation across our tooling.

@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 20, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Aug 20, 2026
Merged via the queue into flutter:master with commit 911c485 Aug 20, 2026
29 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 20, 2026
ybeshkarov added a commit to saymyframe/smf_flutter_cli that referenced this pull request Sep 28, 2026
…utter analyze fails

flutter analyze of Flutter 3.44 fails in a directory whose path has
letters beyond ASCII, on every system: it sends the analysis server a
message whose length it counts in UTF-16 code units rather than in bytes
(fixed in flutter/flutter#191377). In such a
directory the matrix runs dart analyze --fatal-infos, which reports the
same issues, and says so in its log.
ybeshkarov added a commit to saymyframe/smf_flutter_cli that referenced this pull request Sep 28, 2026
…ASCII too

Flutter 3.47.5, the stable one now, still lacks the fix of
flutter/flutter#191377, so the matrix analyzes an app in a directory
with letters beyond ASCII with dart analyze on it as well. The comments
of CI and of the matrix, AGENTS.md and CONTRIBUTING.md name both
versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flutter analyze crashes with FormatException when project path contains non-ASCII characters (Flutter 3.47)

2 participants