{"record":{"id":"c636f4ffa992e86a","repo":"microsoft/typescript-go","slug":"language-client-is-not-initialized","errorCode":null,"errorMessage":"Language client is not initialized","messagePattern":"Language client is not initialized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"_extension/src/client.ts","lineNumber":312,"sourceCode":"        await Promise.all(disposables.map(d => d.dispose()));\r\n        await this.client?.dispose();\r\n    }\r\n\r\n    getCurrentExe(): { path: string; version: string; } | undefined {\r\n        return this.exe;\r\n    }\r\n\r\n    get serverPid(): number | undefined {\r\n        return (this.client as any)?._serverProcess?.pid;\r\n    }\r\n\r\n    /**\r\n     * Initialize an API session and return the socket path for connecting.\r\n     * This allows other extensions to get a direct connection to the API server.\r\n     */\r\n    async initializeAPISession(pipe?: string): Promise<{ sessionId: string; pipe: string; }> {\r\n        if (!this.client) {\r\n            throw new Error(vscode.l10n.t(\"Language client is not initialized\"));\r\n        }\r\n        return this.client.sendRequest<{ sessionId: string; pipe: string; }>(\"custom/initializeAPISession\", { pipe });\r\n    }\r\n\r\n    /**\r\n     * Restart the language server if the executable path has not changed.\r\n     * Returns true if a restart was performed.\r\n     */\r\n    async tryRestart(context: vscode.ExtensionContext): Promise<boolean> {\r\n        if (!this.client) {\r\n            return Promise.reject(new Error(vscode.l10n.t(\"Language client is not initialized\")));\r\n        }\r\n        this.isStopping = false;\r\n        const exe = await getExe(context);\r\n        if (exe.path !== this.exe?.path) {\r\n            return false;\r\n        }\r\n\r","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/_extension/src/client.ts#L294-L330","documentation":"`Client.initializeAPISession` in _extension/src/client.ts lets other extensions get a direct pipe to the language server by sending the LSP request `custom/initializeAPISession`. The underlying vscode-languageclient `LanguageClient` is only constructed inside `Client.start()` (client.ts:205) and is torn down on stop, so calling this API before the session has started (or after it stopped) finds `this.client` undefined and throws this localized error.","triggerScenarios":"Another extension calls `initializeAPISession()` during VS Code startup before the TypeScript Native Preview extension finished activation (exe download/launch), or after the session was stopped/restarted (e.g. user disabled it, or a config change triggered restart). The same guard also protects `tryRestart`.","commonSituations":"Extension-activation races — the consuming extension activates faster than the language server session; calling the exported API in tests without starting the client; the server crashed/stopped and the API is invoked while `client` is unset.","solutions":["Wait for readiness before calling: await the extension's activation completion and its initialized event / check the session's `isInitialized` state (client.ts:53)","Wrap the call in try/catch and retry once after the initialized event fires, since startup is transient","If it persists, check the TypeScript Native Preview output channel — the server may have failed to start (missing exe, crash), which leaves the client uninitialized"],"exampleFix":"// before\nconst session = await tsNativePreview.initializeAPISession(); // throws during startup race\n\n// after\nawait tsNativePreview.waitForInitialization?.() ?? waitUntil(() => tsNativePreview.isInitialized);\nconst session = await tsNativePreview.initializeAPISession();","handlingStrategy":"try-catch","validationCode":"// Before calling the API, confirm the session is up\nconst ext = vscode.extensions.getExtension(\"typescript-native-preview\")!;\nawait ext.activate();\nif (!ext.exports?.isInitialized) {\n  // wait for the extension's initialized event or poll isInitialized before calling\n  await waitFor(() => ext.exports?.isInitialized === true, timeoutMs);\n}","typeGuard":"interface APISessionProvider {\n  isInitialized: boolean;\n  initializeAPISession(pipe?: string): Promise<{ sessionId: string; pipe: string }>;\n}\nfunction isReadySessionProvider(api: unknown): api is APISessionProvider {\n  return !!api && typeof (api as APISessionProvider).initializeAPISession === \"function\"\n    && (api as APISessionProvider).isInitialized === true;\n}","tryCatchPattern":"try {\n  const session = await api.initializeAPISession();\n} catch (e) {\n  if (e instanceof Error && /not initialized/i.test(e.message)) {\n    // transient startup race: wait for the initialized event, retry once\n    await onSessionInitialized();\n    const session = await api.initializeAPISession();\n  } else {\n    throw e; // real failure — surface it (check the output channel for server crashes)\n  }\n}","preventionTips":["Always await the extension's activation and initialized event before using its exported API","Treat 'not initialized' as retryable-once, not as a permanent condition","In tests, start the Client before exercising initializeAPISession, and stop it in afterEach"],"tags":["vscode-extension","language-server","lsp","async","race-condition"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}