vscode-go icon indicating copy to clipboard operation
vscode-go copied to clipboard

debug: failed to launch with error "invalid debug configuration - cannot unmarshal ... into `env`"

Open ssrlive opened this issue 3 years ago • 18 comments

What version of Go, VS Code & VS Code Go extension are you using?

Version Information
  • Run go version to get version of Go from the VS Code integrated terminal.

    • go version go1.18.1 darwin/amd64
  • Run gopls -v version to get version of Gopls from the VS Code integrated terminal.

  • Run code -v or code-insiders -v to get version of VS Code or VS Code Insiders.

    • Version: 1.66.2 Commit: dfd34e8260c270da74b5c2d86d61aee4b6d56977 Date: 2022-04-11T07:49:20.994Z (1 wk ago) Electron: 17.2.0 Chromium: 98.0.4758.109 Node.js: 16.13.0 V8: 9.8.177.11-electron.0 OS: Darwin x64 21.4.0
  • Check your installed extensions to get the version of the VS Code Go extension

  • Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) > Go: Locate Configured Go Tools command.

    • go-outline gotests gomodifytags impl goplay dlv staticcheck gopls

Share the Go related settings you have added/edited

Run Preferences: Open Settings (JSON) command to open your settings.json file. Share all the settings with the go. or ["go"] or gopls prefixes.

Describe the bug

Can NOT debug. Always pop-up this dialog tell me that Failed to launch: invalid debug configuration - cannot unmarshal bool into "env" of type string.

and launch.json is here

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch Package",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}"
        }
    ]
}

I have test the same steps on Linux and everything looks fine.

Screenshots or recordings

Screen Shot 2022-04-22 at 14 56 05

ssrlive avatar Apr 22 '22 07:04 ssrlive

@ssrlive can you enable logging and see if there is any boolean type value among the env property in the launch request the extension is sending to the debug adapter?

@suzmue @polinasok We've seen the extension was sending non-string type env vars to the debug adapter which expects map[string]*string for env. I can think of two options:

  1. relax Delve's type requirement ---> maybe to map[string]interface{}, or
  2. make the extension to check env var elements and stringify if necessary.

What do you prefer?

hyangah avatar Apr 22 '22 19:04 hyangah

@ssrlive To enable the logging, you can use "showLog" and "logOutput":"dap" attributes in your launch.json. It also helps to follow the template and share what you have in settings.json. For example, I can reproduce this issue withh the following in my settings.json

"go.toolsEnvVars": { "BOOL": false}

And this is what's logged:

2022-04-22T15:19:07-07:00 debug layer=dap [<- from client]{"seq":2,"type":"request","command":"launch","arguments":{"name":"Launch file","type":"go","request":"launch","mode":"debug",..."env":{"BOOL":false,"GOPATH":"/Users/polina/go"}...}}

@hyangah Yes, the extension doesn't require strings while dlv does. We likely wanted to be consistent with os.Setenv, which expects string values, when we set the vars.

polinasok avatar Apr 22 '22 22:04 polinasok

Thinking about this more. As per the OS convention, the final values for environment variables must be strings. If users read or set the values in their Go programs, they will deal with them as strings. So it is logical to expect our users to provide all string values in their json maps. Of course, one might argue that we might also want to allow scalars like ints or bools because when environment variables are set on the command line, users can omit the quotes for strings without spaces. But I am not convinced that this is worth the added complexity in either extension or delve code or documentation or error messages.

I think the current message coming from delve is pretty clear and the problem is that the user doesn't realize that the unspecified env in launch.json is populated behind the scenes from go.toolsEnvVars from settings.json. If we want to push error checking and optional stringification into delve, we must log these transformations. And if we do the massaging in the extension, it would still be useful to log which values came from settings.json vs launch.json vs some default for all attributes in the final debug configuration passed to delve. We run into confusion over these with users all the times. And this is yet another example.

So I propose that we:

  1. specify in the description of go.toolsEnvVars and env and envFile that variable values must be strings
  2. check that they are strings when reading these in the extension, so the error messages relate to the original source.
  3. optionally accept and stringify ints, bools, etc.
  4. log any transformations that form the final configuration, so users can still trace where accepted values were coming from if they run into surprises

polinasok avatar Apr 23 '22 06:04 polinasok

my settings.json

{
    "cmake.configureOnOpen": true,
    "explorer.confirmDelete": false,
    "gopls": {
    "build.allowModfileModifications": false
    },
    "go.toolsEnvVars": {
        
    "go.useGoProxyToCheckForToolUpdates":true
    },
    "go.terminal.activateEnvironment": true,
    "go.toolsGopath": ""
}

ssrlive avatar Apr 23 '22 11:04 ssrlive

my settings.json

{
    "cmake.configureOnOpen": true,
    "explorer.confirmDelete": false,
    "gopls": {
    "build.allowModfileModifications": false
    },
    "go.toolsEnvVars": {
        
    "go.useGoProxyToCheckForToolUpdates":true

This boolean true is getting rejected because we expect a string. But is this actually an env variable or an extension setting? I suspect you meant the latter and in that case it should be moved outside of "go.toolsEnvVars" at the same level as other "go.xxx" settings (hover for description once you do that).

},
"go.terminal.activateEnvironment": true,
"go.toolsGopath": ""

}

polinasok avatar Apr 23 '22 17:04 polinasok

@hyangah Is it even right that we pass go.toolsEnvVars intended for Go tools to debuggee? Probably not something we can challenge now as people configurations will break, but definitely something to clarify in the documentation. We have so many ways to set these (go.toolsEnvVars, go.testEnvFile, envFile, env). No wonder users are confused what takes precedence and set to what when (e.g. #452, #2128).

polinasok avatar Apr 23 '22 17:04 polinasok

Starting: /Users/myname/go/bin/dlv dap --check-go-version=false --log=true --log-output=dap --listen=127.0.0.1:54604 --log-dest=3 from /Volumes/mydisk/myapp
DAP server listening at: 127.0.0.1:54604
2022-04-24T11:20:31+08:00 debug layer=dap DAP server pid = 9119
2022-04-24T11:20:31+08:00 debug layer=dap DAP connection 1 started
2022-04-24T11:20:31+08:00 debug layer=dap [<- from client]{"seq":1,"type":"request","command":"initialize","arguments":{"clientID":"vscode","clientName":"Visual Studio Code","adapterID":"go","locale":"en-us","linesStartAt1":true,"columnsStartAt1":true,"pathFormat":"path","supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true,"supportsInvalidatedEvent":true}}
2022-04-24T11:20:31+08:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsFunctionBreakpoints":true,"supportsConditionalBreakpoints":true,"supportsEvaluateForHovers":true,"supportsSetVariable":true,"supportsExceptionInfoRequest":true,"supportTerminateDebuggee":true,"supportsDelayedStackTraceLoading":true,"supportsLogPoints":true,"supportsDisassembleRequest":true,"supportsClipboardContext":true,"supportsSteppingGranularity":true,"supportsInstructionBreakpoints":true}}
2022-04-24T11:20:31+08:00 debug layer=dap [<- from client]{"seq":2,"type":"request","command":"launch","arguments":{"name":"Launch Package","type":"go","request":"launch","mode":"debug","showLog":true,"logOutput":"dap","program":".","__configurationTarget":5,"packagePathToGoModPathMap":{"/Volumes/mydisk/myapp":"/Volumes/mydisk/myapp"},"debugAdapter":"dlv-dap","showRegisters":false,"showGlobalVariables":false,"substitutePath":[],"dlvFlags":[],"hideSystemGoroutines":false,"dlvToolPath":"/Users/myname/go/bin/dlv","env":{"go.useGoProxyToCheckForToolUpdates":true,"GOPATH":"/Users/myname/go"},"__buildDir":"/Volumes/mydisk/myapp","__sessionId":"00cadb8a-6874-4e94-ab76-c7a3cd20f1a6"}}
2022-04-24T11:20:31+08:00 debug layer=dap Failed to launch: invalid debug configuration - cannot unmarshal bool into "env" of type string
2022-04-24T11:20:31+08:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":2,"success":false,"command":"launch","message":"Failed to launch","body":{"error":{"id":3000,"format":"Failed to launch: invalid debug configuration - cannot unmarshal bool into \"env\" of type string","showUser":true}}}

ssrlive avatar Apr 24 '22 03:04 ssrlive

@ssrlive Your settings.json has syntax error.

"go.useGoProxyToCheckForToolUpdates": true shouldn't be an element of "go.toolsEnvVars".

This part

"go.toolsEnvVars": {
        
    "go.useGoProxyToCheckForToolUpdates":true
    },

should be

"go.toolsEnvVars": {
 },  /* or delete "go.toolsEnvVars" setting*/       
 "go.useGoProxyToCheckForToolUpdates":true,

hyangah avatar Apr 24 '22 03:04 hyangah

I don't know, it generate automatically.

ssrlive avatar Apr 24 '22 03:04 ssrlive

The only setting the extension may automatically added is "go.useGoProxyToCheckForToolUpdates": true Since other settings require manual edits, I guess some race occurred while the extension added the setting. 🤷🏽‍♀️ But, correcting the settings error will fix the issue.

Looked through your settings.json, it looks like most settings can be deleted.

{
    "cmake.configureOnOpen": true,
    "explorer.confirmDelete": false,
}

hyangah avatar Apr 24 '22 03:04 hyangah

Change https://go.dev/cl/401974 mentions this issue: package.json: clarify format and precedence of env-setting debug attributes

gopherbot avatar Apr 25 '22 18:04 gopherbot

@polinasok

@hyangah Is it even right that we pass go.toolsEnvVars intended for Go tools to debuggee?

Good point. Since now dlv can process env and the extension directly controls how to start dlv command (in the legacy debug adapter, env is the only way), we can take advantage of it in a more clean way.

  1. update the debug configuration provider and the debug adapter factory to implement:

If debugAdapter == dlv-dap: launch dlv dap with the toolsEnvVars. - handle console=integratedTerminal/externalTerminal case accordingly. pass env verbatim (or env + envFile contents).

  1. specify element types for "env" (https://github.com/golang/vscode-go/blob/27e8258de8d3b5d863e9ba84a0e9b8a8bd7e1b5f/package.json#L670)

hyangah avatar Apr 28 '22 21:04 hyangah

  1. update the debug configuration provider and the debug adapter factory to implement:

If debugAdapter == dlv-dap: launch dlv dap with the toolsEnvVars. - handle console=integratedTerminal/externalTerminal case accordingly. pass env verbatim (or env + envFile contents).

Start dlv with the env settings and let it decide how to combine that with env for debuggee? Makes sense.

  1. specify element types for "env" (https://github.com/golang/vscode-go/blob/27e8258de8d3b5d863e9ba84a0e9b8a8bd7e1b5f/package.json#L670 )

I didn't know how to do this when I updated the comments because typed properties are named. But now I think I found aa way: http://json-schema.org/understanding-json-schema/reference/object.html#pattern-properties

polinasok avatar Apr 29 '22 08:04 polinasok

It looks no one can resolve this bug. this bug will live forever.

ssrlive avatar Jun 08 '22 12:06 ssrlive

Thanks to the discussion here, I was able to fix my issue with using the latest version of vscode-go. But is there a reason why the following settings.json caused issues?

{
    "go.toolsManagement.autoUpdate": true,
    "go.toolsEnvVars": {
        "gopls.env": { /* This caused an error message very similar to the above one except about objects*/
            "GOFLAGS": "-tags=integration unit"
        },
    },
    "go.buildTags": "-tags=integration unit",
    "diffEditor.wordWrap": "on",
    "editor.wordWrap": "on",
    "security.workspace.trust.untrustedFiles": "open",
    "window.zoomLevel": 1
}

Commenting out/removing go.toolsEnvVars fixed the problem.

pjkaufman avatar Jul 06 '22 16:07 pjkaufman

    "go.toolsEnvVars": {
        "gopls.env": { /* This caused an error message very similar to the above one except about objects*/
            "GOFLAGS": "-tags=integration unit"
        },
    },

"go.toolsEnvVars" expects string type key/value. I think this is a malformed setting btw.

hyangah avatar Jul 06 '22 17:07 hyangah

    "go.toolsEnvVars": {
        "gopls.env": { /* This caused an error message very similar to the above one except about objects*/
            "GOFLAGS": "-tags=integration unit"
        },
    },

"go.toolsEnvVars" expects string type key/value. I think this is a malformed setting btw.

Gotcha. It seems that this was either added a ways back by me before it rejected non-string type key value pairs or it was automatically added when I updated a setting. But now that I have removed it, it is working again.

pjkaufman avatar Jul 06 '22 18:07 pjkaufman