{"record":{"id":"3ae81514dc0d3224","repo":"microsoft/typescript-go","slug":"invalid-file-path-path","errorCode":null,"errorMessage":"Invalid file path: \"${path}\"","messagePattern":"Invalid file path: \"(.+?)\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"_packages/native-preview/src/api/fs.ts","lineNumber":96,"sourceCode":"\r\n    function ensureDirectory(segments: string[]): VDirectory {\r\n        let current: VDirectory = root;\r\n        for (const segment of segments) {\r\n            if (!current.children[segment]) {\r\n                current.children[segment] = { type: \"directory\", children: {} };\r\n            }\r\n            else if (current.children[segment].type !== \"directory\") {\r\n                throw new Error(`Cannot create directory: a file already exists at \"/${segments.join(\"/\")}\"`);\r\n            }\r\n            current = current.children[segment] as VDirectory;\r\n        }\r\n        return current;\r\n    }\r\n\r\n    function addToTree(path: string): void {\r\n        const segments = getPathComponents(path).slice(1);\r\n        if (segments.length === 0) {\r\n            throw new Error(`Invalid file path: \"${path}\"`);\r\n        }\r\n        const filename = segments.pop()!;\r\n        const dirNode = ensureDirectory(segments);\r\n        dirNode.children[filename] = { type: \"file\" };\r\n    }\r\n\r\n    function writeFile(path: string, data: string): void {\r\n        content[path] = data;\r\n        addToTree(path);\r\n    }\r\n\r\n    function removeFile(path: string): void {\r\n        delete content[path];\r\n        const segments = getPathComponents(path).slice(1);\r\n        if (segments.length === 0) return;\r\n        const filename = segments.pop()!;\r\n        const dirNode = getNodeFromPath(\"/\" + segments.join(\"/\"));\r\n        if (dirNode && dirNode.type === \"directory\") {\r","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/_packages/native-preview/src/api/fs.ts#L78-L114","documentation":"Thrown by addToTree in createVirtualFileSystem when a path has zero path components after normalization (getPathComponents(path).slice(1).length === 0), i.e., the path denotes the virtual root itself. Only concrete files can be added, so keys like \"\" or \"/\" (or anything that normalizes to the root) are rejected.","triggerScenarios":"Including \"\" or \"/\" as a key in the files map passed to createVirtualFileSystem; the server's writeFile callback sending an empty or root path; dynamically built paths where a join produced an empty string.","commonSituations":"Fixture builders that insert a placeholder key for the root; typos or undefined interpolation producing empty strings in path maps; logging/harness code that mirrors every observed path including the workspace root.","solutions":["Filter degenerate keys before constructing the virtual FS: skip empty strings and paths equal to \"/\"","Fix the path-construction bug that yields an empty/root path (check for undefined segments in joins)","Validate in the writeFile callback that the incoming path names a file, and ignore/log root writes"],"exampleFix":"// before\nconst vfs = createVirtualFileSystem({ \"\": \"\", \"/a.ts\": \"x\" }); // '' -> throws\n\n// after\nconst files = { \"/a.ts\": \"x\" };\nfor (const k of Object.keys(files)) {\n    if (!k || k === \"/\") delete files[k]; // drop root/empty entries\n}\nconst vfs = createVirtualFileSystem(files);","handlingStrategy":"validation","validationCode":"// Drop root/empty keys before constructing the virtual FS\nconst clean: Record<string, string> = {};\nfor (const [p, content] of Object.entries(files)) {\n    const norm = p.replace(/\\\\/g, '/');\n    if (!norm || norm === '/') continue; // cannot add the root itself\n    clean[norm] = content;\n}\nconst vfs = createVirtualFileSystem(clean);","typeGuard":"const isVirtualFilePath = (p: string): boolean => {\n    const norm = p.replace(/\\\\/g, '/');\n    return norm.length > 1 && norm.startsWith('/') && norm !== '/';\n};","tryCatchPattern":"try {\n    vfs.writeFile(path, data);\n} catch (e) {\n    if (e instanceof Error && e.message.includes('Invalid file path')) {\n        // caller sent a root/empty path - log and ignore rather than crash the callback\n        console.warn('writeFile rejected invalid path:', JSON.stringify(path));\n    } else throw e;\n}","preventionTips":["Assert every path names a concrete file under a directory before insertion","Check join() results for empty segments when building paths dynamically","In writeFile callbacks from the server, validate before mutating the tree"],"tags":["virtual-file-system","api","paths","validation","native-preview"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}