Repository navigation
Issue with web-launch-url Parameter Handling on Windows in VS Code #5322
Description
Describe the bug
When using web-launch-url in VS Code on Windows, it fails to pass multiple parameters correctly to the Flutter web app. Despite identical configuration files, this only occurs on Windows, while Linux and macOS handle the parameters as expected.
Details
Using the following configuration from my launch.json file:
{
"name": "example(livekit)",
"cwd": "example",
"request": "launch",
"type": "dart",
"env": {
"DISPLAY": ":0"
},
"args": [
"--web-browser-flag=--disable-web-security",
"--web-port=9080",
"--web-launch-url=http://localhost:9080/?autoConnect&serverUrl=https%3A%2F%2Fmeet.livekit.io&room=123456&name=vscode",
"--dart-entrypoint-args=--autoConnect",
"--dart-entrypoint-args=--serverUrl=https://meet.livekit.io",
"--dart-entrypoint-args=--room=123456",
"--dart-entrypoint-args=--name=vscode",
]
}
https://github.com/AoEiuV020/livekit_meeting/blob/89b0919e4792cfbde3d7f8407733406d30eea1ff/.vscode/launch.json#L30
On Windows, the browser URL launched in the address bar is truncated to:
http://localhost:9080/?autoConnect
All parameters after & are lost, and when targeting Windows, this configuration also causes all subsequent dart-entrypoint-args to be ignored. However, if the web-launch-url is removed, the dart-entrypoint-args function normally.
Running flutter run directly from the command line with parameters works without issue:
flutter run -d chrome "--web-browser-flag=--disable-web-security" "--web-port=9080" "--web-launch-url=http://localhost:9080/?autoConnect&serverUrl=https%3A%2F%2Fmeet.livekit.io&room=123456&name=vscode"
To Reproduce
Steps to reproduce the behavior:
- In VS Code, select the Chrome device as the target.
- Go to the Run and Debug view.
- Select the example (livekit) configuration.
- Click on the Debug button to start the Flutter web app.
Expected behavior
The web-launch-url should consistently retain all query parameters across platforms when launching a Flutter web app from VS Code.
Please complete the following information:
- Operating System and version: win11
- VS Code version: 1.94.2
- Dart extension version: 3.98.1
- Dart/Flutter SDK version: 3.24.4
- Target device (if the issue relates to Flutter debugging): chrome 129.0.6668.101

Activity
DanTup commentedon Oct 28, 2024
I can reproduce this, but I also see it from a PowerShell terminal:
flutter_cli_encoding.mp4
However, if I add
--%to prevent PowerShell parsing the args, it's good:We're just using
Process.start()for this, so I'll need to figure out what escaping Dart is (or isn't) doing for shell execution (since Flutter is a.bat, it has to execute via a shell).DanTup commentedon Oct 28, 2024
Looks like this is documented:
https://api.dart.dev/stable/3.5.4/dart-io/Process/start.html
Looks like the VM has a private implementation of argument escaping here that perhaps we can use:
https://github.com/dart-lang/sdk/blob/6d4ebea83b7217b66112df7268ffc5fa6dd2fd36/sdk/lib/_internal/vm/bin/process_patch.dart#L342
Edit: Apparently that doesn't handle
&:-(DanTup commentedon Oct 28, 2024
I'm actually struggling to track down what's happening here. I wrote a small test script that creates
.batfile that calls a Dart script and passes the args with%*(which is what Flutter does), then calls it with a load of strings with various characters in. Without any escaping, they all come through correctly. With escaping, the escaped values come through to Dart:It's not clear to me why this works given the docs quoted above (and the actual bug reported here). It's going to need some more digging.
修vscode配置windows启动参数无效的问题
DanTup commentedon Nov 25, 2024
Here's a slightly reduced repro that works with Windows desktop, so there's nothing web-specific about this:
DanTup commentedon Nov 25, 2024
I managed to repro this with a Dart script when the executable path contains a space (my Flutter SDK is inside a folder named "Flutter (main)" to catch some issues with escaping like this!). This seems to match some of the description here from the legacy DAP in TS (second line):
Dart-Code/src/shared/processes.ts
Lines 30 to 40 in aac6618
However, moving my Flutter SDK to a folder without a space doesn't prevent the original issue from happening, which seems slightly odd.
In any case, the correct fix here is probably for DAP to escape all of the args and quote them. It's unfortunate because this escaping is probably shell-specific and the rules don't seem complex.
@bkonyi FYI... it would sure be nice if Flutter didn't require a shell script to invoke 😄 For some similar issues with Pub in the past (when it was .bat), I think I bypassed the shell script.. it's possible we could do similar with Flutter (eg. invoke dart.exe and path to the flutter_tools snapshot), but it could be dangerous if the shell script changes - we'd probably need to agree that this is a supported way to invoke it (when we know there's already a Dart SDK downloaded etc.).
bkonyi commentedon Nov 25, 2024
Yeah, I really don't like that
flutter.batanddart.bat(and their.shequivalents) exist. It'd probably be difficult to migrate away from them and still support shipping Flutter via GitHub, so I doubt it'll change any time soon. It's probably safe to assume those artifacts exist if the plugin already knows it's run something likeflutter doctorto initialize the SDK, but poking directly at snapshots is something we discourage since we do change their names from time to time which causes headaches when tooling is reaching into SDK internals.DanTup commentedon Nov 25, 2024
Right, I think I have a good isolated repro for this now...
The script below fails with:
This seems to match what we're seeing with
&in Flutter. I found some rules at https://stackoverflow.com/questions/6427732/how-can-i-escape-an-arbitrary-string-for-use-as-a-command-line-argument-in-windo but in my testing it doesn't seem to work correctly (for ex. doubling up backslashes seems to not work).I'll do some more testing and see if I can come up with some escaping rules that pass for all of those characters and then test it in Flutter.
DanTup commentedon Nov 25, 2024
@bkonyi
Yeah, that's my fear. I kinda wish we had a
dart.exe fluttercommand that just escaped the args correctly and forwarded them on toflutter.batso that every editor wanting to call Flutter didn't have to accurately implement all of the weird Windows shell escaping rules themselves (or more likely, have bugs like this one) 😄Or similar, when Flutter downloads the Dart SDK, it compiles a tiny
flutter.exethat does this forwarding. They're all hacks, but a centralised hack in the SDK might be better than hacks (or bugs) in lots of other places.It's annoying because we're only using shell execute because Flutter is a shell script. We don't actually want any difference in how args are treated, it just happens because the command gets squished to a string to be executed.
Another option could be that when
flutter.batdownloads the SDK, it also compiles a simpleflutter.exealongsideflutter.batthat escapes and forwardsDanTup commentedon Nov 26, 2024
I've not yet found a way to escape
&correctly here, so I've filed dart-lang/sdk#59604 to see if someone can advise how this should work (adding^which I believe should work, does not seem to).DanTup commentedon Nov 26, 2024
Update from dart-lang/sdk#59604... the issue was that flutter.bar uses
%*to forward the args, and that results in everything being expanded to a string again, so that needs escaping again too.We will have to double-escape these for now.. but it would be nice to avoid assumptions about what's inside
flutter.bathere.DanTup commentedon Nov 27, 2024
@bkonyi I'd be interested in your thoughts after reviewing the discussion in dart-lang/sdk#59604 (comment)
I feel like trying to escape things reliably is going to be tough (it seems like we'd need to either make assumptions about
flutter.batand double-escape in DAP, or we'd need to updateflutter.batto do its own escaping of%*properly) and wonder if we should try to find a good way to instead just bypass the shell script from DAP (and maybe VS Code).Some ideas (that I haven't thought through):
flutter.batdoes that is required (I don't think there's much if we know it's initiailized though?)Platform.resolvedExecutableand all of the flags (up to get-execution-info) in a machine-parseable away, so it is a way to find out how to invokeflutterwithout the shell script, but it forcesflutter.batto run (and perform any initialization) and avoids hard-coding any knowledge of dart.exe or the args that the shell script adds.All solutions feel like hacks, but I feel like they're less hacky than trying to handle this escaping. It's bananas (in particular because of %* in the bat file meaning we need to either escape twice in the client, or add escaping to the bat file.. though I haven't been able to make that work right).
Wdestroier commentedon Mar 6, 2025
Hi @DanTup, I'm not sure if the issue is related, but I'm trying to launch Flutter on http://localhost:3000 and opening Chrome on https://localhost:5173/f/ by setting the
--web-launch-urlflag, but it's launching on http://localhost:3000/f. That's the behavior when I click the "Run" button above themainmethod to launch the app.I want to open Chrome on another URL because I setup a reverse proxy to deal with CORS and Cookies. The following message is printed when I press CTRL+F5 to launch the app:
Another issue is clicking "Run" or pressing CTRL+F5 leads to different results. For example: I prefer to click the "Run" button, but then Flutter is launched on a random port (completely ignoresI learned VSCode is similar to Visual Studio (F5 runs in Debug mode)launch.json). I applied this workaround to improve the experience: https://stackoverflow.com/a/76259368. Edit: to complement, a system-wide setting is not ideal, but running the app by pressing CTRL+F5 is bad (must remember about the shortcut and breakpoints don't work).and apparently there's no workaround to fix the "Run" button.DanTup commentedon Mar 6, 2025
No, I don't think it's related - but please file a new issue about this so we can track down where it's being changed.
This is somewhat expected, because pressing F5 will launch your active debug configuration (which can be selected on the Debug sidebar) whereas the Run/Debug links always run a default launch configuration with the appropriate file (and possibly args, if it's a test/group) set. You can override this behaviour by marking a launch configuration (in launch.json) as a
templateForin which case it can be used for the Run/Debug CodeLens links - see https://dartcode.org/docs/launch-configuration/.DanTup commentedon Mar 6, 2025
I misread your original issue thinking the trailing slash was the issue, but now I see it's HTTPS. I believe this is a result of this regex here:
https://github.com/flutter/flutter/blob/099e6d39fe38dbda78dd5efb7d8424bf7fd845a2/packages/flutter_tools/lib/src/web/web_device.dart#L119
I suspect that regex could have
s?added to it to fix this if it is only used for launching the browser, but if you're also expecting the server to listen on HTTPS (eg. you're not proxying it yourself) then probably it would require work for the internal web server to use HTTPS. This was noted at flutter/flutter#95002 (comment).Wdestroier commentedon Mar 6, 2025
Amazing, it works! It's a great QoL improvement, thank you.
I was searching the codebase and found this code too. The reverse proxy is adding TLS, not throwing the error would be enough.
Thank you for the answers!
Support launching a HTTPS URL (#164720)
Support launching a HTTPS URL (flutter#164720)
Support launching a HTTPS URL (flutter#164720)
Support launching a HTTPS URL (flutter#164720)
Support launching a HTTPS URL (flutter#164720)
Support launching a HTTPS URL (#164720)