microsoft/typescript-go · error

invalid URI: ${uri}

Error message

invalid URI: ${uri}

What it means

In documentURIToFileName, any URI that is not 'bundled://' and not 'file://' is treated as scheme-based and converted to the dynamic '^/scheme/authority/path' form. This requires a ':' separating the scheme from the rest. A string without a colon has no scheme at all, so it is not a URI in any recognizable sense and the function throws rather than guessing.

Source

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

        }

        // 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;
    }

    // Leave all other URIs escaped so we can round-trip them.
    // Convert to dynamic file name format: ^/scheme/authority/path

    const colonIndex = uri.indexOf(":");
    if (colonIndex === -1) {
        throw new Error("invalid URI: " + uri);
    }

    const scheme = uri.substring(0, colonIndex);
    let path = uri.substring(colonIndex + 1);

    let authority = "ts-nul-authority";
    if (path.startsWith("//")) {
        const rest = path.substring(2);
        const slashIndex = rest.indexOf("/");
        if (slashIndex === -1) {
            throw new Error("invalid URI: " + uri);
        }
        authority = rest.substring(0, slashIndex);
        path = rest.substring(slashIndex + 1);
    }

    return "^/" + scheme + "/" + authority + "/" + path;
}

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Convert plain paths to 'file://' URIs first (or call fileNameToDocumentURI which accepts raw paths)
  2. If integrating with LSP, ensure textDocument URIs are used, not fileName fields
  3. Pre-check uri.includes(':') and handle the path case separately

Example fix

// before
documentURIToFileName("/home/user/project/a.ts"); // throws: no scheme

// after
documentURIToFileName("file:///home/user/project/a.ts");
Defensive patterns

Strategy: validation

Validate before calling

const looksLikeUri = (s: string) => /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(s);

Type guard

function isDocumentUri(s: string): boolean {
  return s.startsWith("bundled:///") || s.startsWith("file://") || /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(s);
}

Try / catch

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

Prevention

When it happens

Trigger: Calling documentURIToFileName with a bare path: 'src/index.ts', './foo.ts', '/abs/path/file.ts' (POSIX absolute paths start with '/', not 'file://'), or any relative/extensionless string with no scheme.

Common situations: Passing file system paths where document URIs are expected — e.g. feeding LSP document URIs from an editor but forgetting some clients send raw paths; migration from APIs that accepted both paths and URIs.

Related errors


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