microsoft/typescript-go · error

invalid file URI: ${uri}

Error message

invalid file URI: ${uri}

What it means

documentURIToFileName parses 'file://' URIs with the WHATWG URL constructor. If URL construction fails — malformed percent-encoding, invalid host characters, or a URL the parser rejects — the catch block rethrows as 'invalid file URI'. The library throws instead of returning garbage because a bad file URI would silently corrupt path round-tripping.

Source

Thrown at _packages/native-preview/src/api/path.ts:509

 * documentURIToFileName("file:///path/to/file.ts") === "/path/to/file.ts"
 * documentURIToFileName("file:///c%3A/path/to/file.ts") === "c:/path/to/file.ts"
 * documentURIToFileName("untitled:Untitled-1") === "^/untitled/ts-nul-authority/Untitled-1"
 * documentURIToFileName("vscode-vfs://github/microsoft/typescript-go/file.ts") === "^/vscode-vfs/github/microsoft/typescript-go/file.ts"
 */
export function documentURIToFileName(uri: string): string {
    // Bundled files are returned as-is
    if (isBundled(uri)) {
        return uri;
    }

    // Handle file:// URIs
    if (uri.startsWith("file://")) {
        let parsed: URL;
        try {
            parsed = new URL(uri);
        }
        catch {
            throw new Error("invalid file URI: " + uri);
        }

        // UNC path: file://server/share/...
        if (parsed.host !== "") {
            return "//" + parsed.host + parsed.pathname;
        }

        // Local file - fix Windows path by removing leading slash before volume
        const path = decodeURIComponent(parsed.pathname);
        if (path.length >= 3 && path.charCodeAt(0) === CharacterCodesSlash) {
            const [volume, rest, ok] = splitVolumePath(path.substring(1));
            if (ok) {
                return volume + rest;
            }
        }
        return path;
    }

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Percent-encode each path segment before building the URI (the library's own fileNameToDocumentURI does this via encodeURIComponent)
  2. Run new URL(uri) in a try/catch yourself first to give a better error
  3. Replace literal backslashes and raw special characters ('#','?','%', space) with their encoded forms

Example fix

// before
documentURIToFileName("file:///C:/My Files/a%b.ts"); // '%b' is bad encoding -> throws

// after
documentURIToFileName("file:///C:/My%20Files/a%25b.ts");
Defensive patterns

Strategy: validation

Validate before calling

const isParsableFileUri = (uri: string) => {
  if (!uri.startsWith("file://")) return true;
  try { new URL(uri); return true; } catch { return false; }
};

Try / catch

try { name = documentURIToFileName(uri); } catch (e) { if ((e as Error).message.startsWith("invalid file URI")) { uri = encodeURI(uri); name = documentURIToFileName(uri); } else throw e; }

Prevention

When it happens

Trigger: Passing a string that starts with 'file://' but is not parseable by new URL(): 'file://%zz', 'file://C|/path', 'file://' + raw unencoded unicode/pipe characters, or double-encoded strings where '%' survives unescaped.

Common situations: Concatenating 'file://' + windowsPath without encodeURIComponent (pipes, spaces, non-ASCII break URL); receiving URIs from LSP clients that send raw paths; copy/paste of URIs with literal backslashes or unencoded '#'/'?'.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/a4f61d2eba5c709a. Report an issue: GitHub.