{"record":{"id":"aee1a9690cce4326","repo":"GoogleContainerTools/skaffold","slug":"expected-workspacefolders-to-have-at-least-one-val","errorCode":null,"errorMessage":"expected WorkspaceFolders to have at least one value, got 0","messagePattern":"expected WorkspaceFolders to have at least one value, got 0","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/lsp/handler.go","lineNumber":117,"sourceCode":"\t\tdefer func() {\n\t\t\terr := recover()\n\t\t\tif err != nil {\n\t\t\t\tlog.Entry(ctx).Errorf(\"recovered from panic at %s: %v\\n\", req.Method(), err)\n\t\t\t\tlog.Entry(ctx).Errorf(\"stacktrace from panic: \\n%s\", string(debug.Stack()))\n\t\t\t}\n\t\t}()\n\t\tlog.Entry(ctx).Debugf(\"req.Method():  %q\\n\", req.Method())\n\t\tswitch req.Method() {\n\t\tcase protocol.MethodInitialize:\n\t\t\tvar params protocol.InitializeParams\n\t\t\tjson.Unmarshal(req.Params(), &params)\n\t\t\tlog.Entry(ctx).Debugf(\"InitializeParams: %+v\\n\", params)\n\t\t\tlog.Entry(ctx).Debugf(\"InitializeParams.Capabilities.TextDocument: %+v\\n\", params.Capabilities.TextDocument)\n\t\t\t// TODO(aaron-prindle) currently this only supports workspaces of length one (or the first of the list of workspaces)\n\t\t\t// This used to be a single workspace field/value before lsp spec changes and I only know how to open one workspace per\n\t\t\t// session in VSCode atm so this should be ok initially\n\t\t\tif len(params.WorkspaceFolders) == 0 {\n\t\t\t\treturn fmt.Errorf(\"expected WorkspaceFolders to have at least one value, got 0\")\n\t\t\t}\n\t\t\t// TODO(aaron-prindle) does workspace changing send a new 'initialize' or is there workspaceChange msg?  Need to make sure that is handled...\n\t\t\t// and we don't keep initialize workspace always\n\t\t\terr := os.Chdir(uriToFilename(uri.URI(params.WorkspaceFolders[0].URI)))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// TODO(aaron-prindle) might need some checks to verify the initialize requests supports these,\n\t\t\t// right now assuming VS Code w/ supported methods - seems like an ok assumption for now\n\t\t\tif err := reply(ctx, protocol.InitializeResult{\n\t\t\t\tCapabilities: protocol.ServerCapabilities{\n\t\t\t\t\tTextDocumentSync: protocol.TextDocumentSyncOptions{\n\t\t\t\t\t\tChange:    protocol.TextDocumentSyncKindFull,\n\t\t\t\t\t\tOpenClose: true,\n\t\t\t\t\t\tSave: &protocol.SaveOptions{\n\t\t\t\t\t\t\tIncludeText: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/lsp/handler.go#L99-L135","documentation":"Skaffold's LSP server, on receiving the LSP 'initialize' request, requires params.WorkspaceFolders to contain at least one workspace because it chdirs into the first folder and supports only one workspace per session. When the client sends an initialize request with zero workspace folders, this error is returned.","triggerScenarios":"An LSP client (or hand-rolled LSP test client) sends an Initialize request with WorkspaceFolders empty or omitted; older clients that predate workspace-folders support send only rootUri/rootPath (or neither).","commonSituations":"Testing the LSP server with a minimal client that forgets WorkspaceFolders; an editor integration opening a single file with no workspace; protocol version mismatches where folders were sent in the legacy rootUri field.","solutions":["Send the workspace root in InitializeParams.WorkspaceFolders (name + URI) when initializing the client","If the client only supports rootUri/rootPath, upgrade it or convert rootUri into a single WorkspaceFolders entry in your adapter","For tests, construct params with WorkspaceFolders: []WorkspaceFolder{{URI: \"file:///path/to/workspace\"}}"],"exampleFix":"// before: client sends\nparams := InitializeParams{} // no WorkspaceFolders\n// after\nparams := InitializeParams{\n    WorkspaceFolders: []WorkspaceFolder{{\n        Name: \"my-project\",\n        URI:  \"file:///home/dev/my-project\",\n    }},\n}","handlingStrategy":"validation","validationCode":"// client side, before sending initialize\nif len(params.WorkspaceFolders) == 0 && params.RootURI != \"\" {\n    params.WorkspaceFolders = []WorkspaceFolder{{Name: filepath.Base(params.RootURI), URI: params.RootURI}}\n}\nif len(params.WorkspaceFolders) == 0 {\n    return errors.New(\"cannot initialize skaffold LSP without a workspace folder\")\n}","typeGuard":"func hasWorkspaceFolders(p InitializeParams) bool { return len(p.WorkspaceFolders) > 0 }","tryCatchPattern":"err := initializeHandler(ctx, conn, params)\nif err != nil && strings.Contains(err.Error(), \"expected WorkspaceFolders\") {\n    return jsonrpc2.NewError(codeInvalidParams, \"initialize requires at least one workspaceFolder\")\n}","preventionTips":["Always populate WorkspaceFolders in InitializeParams when writing LSP clients/tests","Convert legacy rootUri/rootPath into a single WorkspaceFolders entry","Do not open single files without a workspace against this server","Handle the invalid-params JSON-RPC error gracefully on the client to prompt for a folder"],"tags":["lsp","workspace","initialization"],"backgroundTag":"missing-workspace-folders","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}