{"record":{"id":"0a8dc1a293109be8","repo":"ramensoftware/windhawk","slug":"no-workspace-folder","errorCode":null,"errorMessage":"No workspace folder","messagePattern":"No workspace folder","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/windhawk-vscode/src/utils/editorWorkspaceUtils.ts","lineNumber":20,"sourceCode":"import * as path from 'path';\nimport * as child_process from 'child_process';\nimport * as vscode from 'vscode';\nimport config from '../config';\n\n// The charset the core enforces on a mod's @id (domain validate_metadata), kept\n// here because ids reach paths by plain interpolation and sanitize nothing.\nfunction isValidModId(modId: string) {\n\treturn /^[0-9a-z-]+$/.test(modId);\n}\n\nexport default class EditorWorkspaceUtils {\n\tprivate workspacePath: string;\n\n\tpublic constructor() {\n\t\tconst firstWorkspaceFolder = vscode.workspace.workspaceFolders?.[0];\n\t\tif (!firstWorkspaceFolder) {\n\t\t\tvscode.commands.executeCommand('workbench.action.files.openFolder');\n\t\t\tthrow new Error('No workspace folder');\n\t\t}\n\n\t\tthis.workspacePath = firstWorkspaceFolder.uri.fsPath;\n\t}\n\n\tpublic getFilePath(fileName: string) {\n\t\treturn path.join(this.workspacePath, fileName);\n\t}\n\n\tpublic getWorkspaceFolder() {\n\t\treturn this.workspacePath;\n\t}\n\n\tpublic getModSourcePath() {\n\t\treturn this.getFilePath('mod.wh.cpp');\n\t}\n\n\tpublic writePchHeader(content: string) {","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk-vscode/src/utils/editorWorkspaceUtils.ts#L2-L38","documentation":"EditorWorkspaceUtils requires a VS Code workspace to resolve mod file paths. In its constructor it reads the first entry of vscode.workspace.workspaceFolders; if the array is empty or undefined (no folder open), it triggers the 'workbench.action.files.openFolder' dialog and throws this error instead of constructing in an invalid state.","triggerScenarios":"Instantiating new EditorWorkspaceUtils() (directly or via a command/registration that constructs it) while VS Code has no workspace folder open — e.g. running a Windhawk extension command from an empty window or a single untitled file with no folder.","commonSituations":"Launching a fresh VS Code window and invoking a mod-related command before opening a folder; automation/test harnesses that activate the extension without a workspace; remote scenarios where the workspace failed to load.","solutions":["Open a workspace folder first (File > Open Folder); the constructor already pops the open-folder dialog, so just choose a folder and retry the command.","Check vscode.workspace.workspaceFolders?.length > 0 before invoking commands that construct EditorWorkspaceUtils.","If this happens in tests or automation, create/open a workspace (vscode.openFolder or a multi-root workspace file) in setup before the extension runs."],"exampleFix":"// before\nconst utils = new EditorWorkspaceUtils();\n// after\nif (vscode.workspace.workspaceFolders?.length) {\n  const utils = new EditorWorkspaceUtils();\n} else {\n  vscode.window.showErrorMessage('Open a folder first.');\n}","handlingStrategy":"try-catch","validationCode":"if (!vscode.workspace.workspaceFolders?.length) {\n  vscode.window.showErrorMessage('Open a workspace folder before using this command.');\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const utils = new EditorWorkspaceUtils();\n} catch (e) {\n  if (e.message === 'No workspace folder') {\n    // constructor already offered the open-folder dialog; abort quietly\n    return;\n  }\n  throw e;\n}","preventionTips":["Gate workspace-dependent commands with a workspaceFolders check or enablement clause in package.json (e.g. when clause 'workspaceFolderCount > 0').","In tests/automation, always open a folder before activating the extension.","Handle the constructor's throw as a normal 'user must open a folder' flow, not a bug."],"tags":["vscode","workspace","precondition"],"backgroundTag":"missing-required-config","analyzedSha":"61d99ed8e182e1af1b60109612b6763ad1b4b74e","analyzedAt":"2026-09-12T14:02:41.115Z","contentChangedAt":"2026-09-12T14:02:41.115Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}