diff --git a/src/main/managed-server/install/orcad-remote-context.ts b/src/main/managed-server/install/orcad-remote-context.ts
index b7d3a7dfbd1..ab1f332622f 100644
--- a/src/main/managed-server/install/orcad-remote-context.ts
+++ b/src/main/managed-server/install/orcad-remote-context.ts
@@ -56,7 +56,11 @@ export async function resolveOrcadRemoteContext> {
const host = detectedHost ?? (await detectRemoteHostPlatform(connection, { signal }))
if (!host) {
- throw new OrcadHostUnsupportedError('Orca’s server doesn’t support this SSH host’s platform.')
+ throw new OrcadHostUnsupportedError(
+ isWslOrcadHostTarget(target)
+ ? 'Orca’s server doesn’t support this WSL distro’s platform. Use an x64 or arm64 Linux distro.'
+ : 'Orca’s server doesn’t support this SSH host’s platform.'
+ )
}
const remote = { conn: connection, host, signal }
const { orcadHome: remoteHome, userDataDir } = await resolveOrcadMachineHome(
diff --git a/src/main/managed-server/lifecycle/orcad-runtime-target.ts b/src/main/managed-server/lifecycle/orcad-runtime-target.ts
index e58ab279076..347cbf9ac83 100644
--- a/src/main/managed-server/lifecycle/orcad-runtime-target.ts
+++ b/src/main/managed-server/lifecycle/orcad-runtime-target.ts
@@ -5,6 +5,13 @@ import type { OrcadHostTransport } from '../../ssh/orcad-host-transport'
import { pinnedRuntimeTargetForHost } from '../../ssh/pinned-runtime-host-target'
import type { RemoteHostPlatform } from '../../ssh/ssh-remote-platform'
+/** Lets a caller that knows the host kind add its own fix; the message is the one SSH shows. */
+export class OrcadHostGlibcUnsupportedError extends OrcadHostUnsupportedError {
+ constructor(target: string, glibc: string) {
+ super(`No Orca runtime supports ${target} with glibc ${glibc}.`)
+ }
+}
+
export async function resolveOrcadRuntimeTarget(options: {
conn: OrcadHostTransport
host: RemoteHostPlatform
@@ -15,9 +22,7 @@ export async function resolveOrcadRuntimeTarget(options: {
const target = pinnedRuntimeTargetForHost(facts)
if (!target) {
const glibc = facts.glibc ? `${facts.glibc.major}.${facts.glibc.minor}` : 'unknown'
- throw new OrcadHostUnsupportedError(
- `No Orca runtime supports ${facts.target} with glibc ${glibc}.`
- )
+ throw new OrcadHostGlibcUnsupportedError(facts.target, glibc)
}
return target
}
diff --git a/src/main/wsl/wsl-distro-unsupported.test.ts b/src/main/wsl/wsl-distro-unsupported.test.ts
new file mode 100644
index 00000000000..f33b63e3cbf
--- /dev/null
+++ b/src/main/wsl/wsl-distro-unsupported.test.ts
@@ -0,0 +1,68 @@
+import { describe, expect, it } from 'vitest'
+import { classifyOrcadHostUnavailable } from '../orcad/orcad-host-unavailable'
+import { OrcadHostGlibcUnsupportedError } from '../managed-server/lifecycle/orcad-runtime-target'
+import { RemoteNodeRuntimeSelfTestError } from '../ssh/orcad-remote-node-runtime-report'
+import {
+ isWslDistroNotFoundFailure,
+ WslDistroNotRegisteredError,
+ WslDistroVersion1Error,
+ wslUnsupportedDistroFixMessage
+} from './wsl-distro-unsupported'
+
+const NIXOS_STUB_OUTPUT =
+ 'Could not start dynamically linked executable: node\n' +
+ 'NixOS cannot run dynamically linked executables intended for generic\n' +
+ 'linux environments out of the box.'
+
+describe('distros that cannot host Orca', () => {
+ it('says how to convert a WSL 1 distro', () => {
+ expect(new WslDistroVersion1Error('Legacy').message).toContain('wsl --set-version Legacy 2')
+ })
+
+ it('classifies both refusals as an unsupported host, as the SSH path records them', () => {
+ expect(classifyOrcadHostUnavailable(new WslDistroVersion1Error('Legacy'))).toBe(
+ 'unsupported_host'
+ )
+ expect(classifyOrcadHostUnavailable(new WslDistroNotRegisteredError('Gone'))).toBe(
+ 'unsupported_host'
+ )
+ })
+
+ it.each([
+ ['the English sentence', 'There is no distribution with the supplied name.', true],
+ [
+ 'the error code under a localized sentence',
+ 'Fehler: Wsl/Service/WSL_E_DISTRO_NOT_FOUND',
+ true
+ ],
+ ['an unrelated failure', 'Command "uname -r" failed (exit 1): timeout', false]
+ ])('recognizes a missing distro from %s', (_case, message, expected) => {
+ expect(isWslDistroNotFoundFailure(new Error(message))).toBe(expected)
+ })
+
+ it('adds the glibc fix for a distro, leaving the shared refusal SSH shows as it was', () => {
+ const error = new OrcadHostGlibcUnsupportedError('linux-arm64-glibc', '2.27')
+ expect(error.name).toBe('OrcadHostUnsupportedError')
+ expect(error.message).toBe('No Orca runtime supports linux-arm64-glibc with glibc 2.27.')
+ expect(wslUnsupportedDistroFixMessage(error)).toBe(
+ 'No Orca runtime supports linux-arm64-glibc with glibc 2.27. Use a Linux release with ' +
+ 'glibc 2.28 or newer (for example Ubuntu 20.04 or Debian 10 and later).'
+ )
+ })
+
+ it('tells a NixOS distro to turn on nix-ld, leaving the shared self-test wording as it was', () => {
+ const error = new RemoteNodeRuntimeSelfTestError(127, NIXOS_STUB_OUTPUT)
+ expect(error.message).toMatch(/^The pinned Node runtime did not run on the host \(exit 127\)/)
+ const fix = wslUnsupportedDistroFixMessage(error)
+ expect(fix).toMatch(/^NixOS can’t run Orca’s Node runtime/)
+ expect(fix).toContain('programs.nix-ld.enable = true;')
+ expect(fix).toContain(`(exit 127: ${NIXOS_STUB_OUTPUT})`)
+ })
+
+ it('has no fix for other failures', () => {
+ expect(
+ wslUnsupportedDistroFixMessage(new RemoteNodeRuntimeSelfTestError(139, 'Segmentation fault'))
+ ).toBeNull()
+ expect(wslUnsupportedDistroFixMessage(new Error('bridge refused'))).toBeNull()
+ })
+})
diff --git a/src/main/wsl/wsl-distro-unsupported.ts b/src/main/wsl/wsl-distro-unsupported.ts
new file mode 100644
index 00000000000..b11d819d169
--- /dev/null
+++ b/src/main/wsl/wsl-distro-unsupported.ts
@@ -0,0 +1,70 @@
+/**
+ * Distros that can't host Orca's server, each refused with the step that fixes it. There is no
+ * fallback once the WSL bridge is gone, so a refusal must say what to run, not only what failed.
+ */
+import { OrcadHostUnsupportedError } from '../orcad/orcad-host-unavailable'
+import { OrcadHostGlibcUnsupportedError } from '../managed-server/lifecycle/orcad-runtime-target'
+import { RemoteNodeRuntimeSelfTestError } from '../ssh/orcad-remote-node-runtime-report'
+
+export function wsl1DistroMessage(distro: string): string {
+ return (
+ `${distro} runs WSL 1, which Orca no longer supports. ` +
+ `Convert it to WSL 2 in a Windows terminal with: wsl --set-version ${distro} 2`
+ )
+}
+
+export function wslDistroNotRegisteredMessage(distro: string): string {
+ return (
+ `${distro} is not an installed WSL distro. ` +
+ 'Run wsl --list --verbose in a Windows terminal to see the installed ones, ' +
+ 'or reinstall it and try again.'
+ )
+}
+
+/** Keeps OrcadHostUnsupportedError's name, so callers that classify by name still see it. */
+export class WslDistroVersion1Error extends OrcadHostUnsupportedError {
+ constructor(distro: string) {
+ super(wsl1DistroMessage(distro))
+ }
+}
+
+export class WslDistroNotRegisteredError extends OrcadHostUnsupportedError {
+ constructor(distro: string) {
+ super(wslDistroNotRegisteredMessage(distro))
+ }
+}
+
+// wsl.exe localizes its sentence but not the error code that newer builds print after it.
+const DISTRO_NOT_FOUND = /WSL_E_DISTRO_NOT_FOUND|There is no distribution with the supplied name/i
+
+export function isWslDistroNotFoundFailure(error: unknown): boolean {
+ return error instanceof Error && DISTRO_NOT_FOUND.test(error.message)
+}
+
+/** Rethrows wsl.exe's missing-distro failure as the refusal that says how to fix it. */
+export function refuseMissingWslDistro(distro: string): (error: unknown) => never {
+ return (error) => {
+ throw isWslDistroNotFoundFailure(error) ? new WslDistroNotRegisteredError(distro) : error
+ }
+}
+
+// NixOS's stub loader refuses generic Linux binaries with this sentence.
+const NIXOS_STUB_LOADER = /NixOS cannot run dynamically linked executables/
+
+/** The shared server refusal plus the step that fixes it in a distro; null when there is none. */
+export function wslUnsupportedDistroFixMessage(error: unknown): string | null {
+ if (error instanceof OrcadHostGlibcUnsupportedError) {
+ return (
+ `${error.message} Use a Linux release with glibc 2.28 or newer ` +
+ '(for example Ubuntu 20.04 or Debian 10 and later).'
+ )
+ }
+ if (error instanceof RemoteNodeRuntimeSelfTestError && NIXOS_STUB_LOADER.test(error.output)) {
+ return (
+ 'NixOS can’t run Orca’s Node runtime as it is. Turn on nix-ld ' +
+ '(programs.nix-ld.enable = true; in configuration.nix), run nixos-rebuild switch, ' +
+ `then reconnect. (exit ${error.exitStatus ?? 'unknown'}: ${error.output})`
+ )
+ }
+ return null
+}
diff --git a/src/main/wsl/wsl-host-add-admission.ts b/src/main/wsl/wsl-host-add-admission.ts
index 81420eb5379..aa0f17a636e 100644
--- a/src/main/wsl/wsl-host-add-admission.ts
+++ b/src/main/wsl/wsl-host-add-admission.ts
@@ -2,6 +2,7 @@
import type { WslHostAddResult } from '../../shared/wsl-host-types'
import type { WslHostDistroCandidate } from './wsl-host-distro-list'
import { wslDistroHolderKey } from './wsl-distro-holder-record'
+import { wsl1DistroMessage, wslDistroNotRegisteredMessage } from './wsl-distro-unsupported'
export const WSL_HOSTS_DISABLED_MESSAGE = 'WSL hosts are turned off in Settings → Experimental.'
export const WSL_HOST_SERVER_FILES_MISSING_MESSAGE =
@@ -53,14 +54,14 @@ export function admitWslHostDistro(args: {
return {
ok: false,
kind: 'failed',
- message: `${args.requested} is not a registered WSL distro.`
+ message: wslDistroNotRegisteredMessage(args.requested)
}
}
if (distro.version === 1) {
return {
ok: false,
kind: 'unsupported-wsl1',
- message: `${distro.name} runs WSL 1, which isn’t supported as a host. Convert it with: wsl --set-version ${distro.name} 2`
+ message: wsl1DistroMessage(distro.name)
}
}
if (args.alreadyAdded(distro.name)) {
diff --git a/src/main/wsl/wsl-host-first-connect.ts b/src/main/wsl/wsl-host-first-connect.ts
index 62e30e2efb8..b3b2afe6d3c 100644
--- a/src/main/wsl/wsl-host-first-connect.ts
+++ b/src/main/wsl/wsl-host-first-connect.ts
@@ -4,6 +4,8 @@ import type { WslHostAddResult } from '../../shared/wsl-host-types'
import { OrcadHostUnsupportedError } from '../orcad/orcad-host-unavailable'
import type { WslHostConnector } from './wsl-host-service'
import { WslOrcadLaunchDeferredError } from './wsl-orcad-connection-errors'
+import { WslDistroVersion1Error, wslUnsupportedDistroFixMessage } from './wsl-distro-unsupported'
+import { RemoteNodeRuntimeSelfTestError } from '../ssh/orcad-remote-node-runtime-report'
import type { WslOrcadConnection } from './wsl-orcad-connection'
type WslHostAddRefusal = Extract
@@ -30,8 +32,8 @@ export async function connectForWslHostAdd(
}
return {
ok: false,
- kind: error instanceof OrcadHostUnsupportedError ? 'unsupported-wsl1' : 'failed',
- message: errorMessage(error)
+ kind: connectFailureKind(error),
+ message: wslUnsupportedDistroFixMessage(error) ?? errorMessage(error)
}
}
const refusal = lateRefusal()
@@ -41,3 +43,14 @@ export async function connectForWslHostAdd(
}
return { connection }
}
+
+/** A distro Orca can't run in reads apart from a connect that may work on retry. */
+function connectFailureKind(error: unknown): WslHostAddRefusal['kind'] {
+ if (error instanceof WslDistroVersion1Error) {
+ return 'unsupported-wsl1'
+ }
+ return error instanceof OrcadHostUnsupportedError ||
+ error instanceof RemoteNodeRuntimeSelfTestError
+ ? 'unsupported-distro'
+ : 'failed'
+}
diff --git a/src/main/wsl/wsl-host-service.test.ts b/src/main/wsl/wsl-host-service.test.ts
index 5589c4fe90e..be8a33e587d 100644
--- a/src/main/wsl/wsl-host-service.test.ts
+++ b/src/main/wsl/wsl-host-service.test.ts
@@ -13,6 +13,8 @@ import { getWslHostDeploymentStorePath } from '../../shared/wsl-host-deployment-
import { getPreferredPairingOffer } from '../../shared/runtime-environments'
import type { WslHostStatus } from '../../shared/wsl-host-types'
import { OrcadHostUnsupportedError } from '../orcad/orcad-host-unavailable'
+import { RemoteNodeRuntimeSelfTestError } from '../ssh/orcad-remote-node-runtime-report'
+import { wsl1DistroMessage, WslDistroVersion1Error } from './wsl-distro-unsupported'
import { WslHostService, type WslHostConnector } from './wsl-host-service'
import { wakeRememberedWslHosts } from './wsl-host-early-wake'
import { WslOrcadLaunchDeferredError } from './wsl-orcad-connection-errors'
@@ -773,10 +775,17 @@ describe('WslHostService', () => {
})
it.each([
+ ['unsupported-wsl1', () => new WslDistroVersion1Error('Ubuntu'), wsl1DistroMessage('Ubuntu')],
[
- 'unsupported-wsl1',
- () => new OrcadHostUnsupportedError('WSL 1 cannot run the Orca server.'),
- 'WSL 1 cannot run the Orca server.'
+ 'unsupported-distro',
+ () => new OrcadHostUnsupportedError('No Orca runtime supports linux-arm64-glibc.'),
+ 'No Orca runtime supports linux-arm64-glibc.'
+ ],
+ [
+ 'unsupported-distro',
+ () =>
+ new RemoteNodeRuntimeSelfTestError(127, 'libstdc++.so.6: cannot open shared object file'),
+ expect.stringContaining('apk add libstdc++')
],
['failed', () => new Error('bridge refused'), 'bridge refused']
])(
diff --git a/src/main/wsl/wsl-orcad-deploy.test.ts b/src/main/wsl/wsl-orcad-deploy.test.ts
index c80d3baee31..de77feb8213 100644
--- a/src/main/wsl/wsl-orcad-deploy.test.ts
+++ b/src/main/wsl/wsl-orcad-deploy.test.ts
@@ -209,7 +209,25 @@ describe('deployAndLaunchWslOrcad', () => {
it('refuses a WSL 1 distro before holding it or touching its files', async () => {
await expect(launch('4.4.0-19041-Microsoft')).rejects.toMatchObject({
- name: 'OrcadHostUnsupportedError'
+ name: 'OrcadHostUnsupportedError',
+ message: expect.stringContaining('wsl --set-version Ubuntu-24.04 2')
+ })
+ expect(mocks.steps).toEqual(['uname'])
+ })
+
+ it('tells an unregistered distro how to find the installed ones, before holding anything', async () => {
+ mocks.exec.mockImplementation(async () => {
+ mocks.steps.push('uname')
+ throw new Error(
+ 'Command "uname -r" failed (exit 1): There is no distribution with the supplied name.\n' +
+ 'Error code: Wsl/Service/WSL_E_DISTRO_NOT_FOUND'
+ )
+ })
+ await expect(
+ deployAndLaunchWslOrcad('Gone', { holder: holder(), createTransport: transport })
+ ).rejects.toMatchObject({
+ name: 'OrcadHostUnsupportedError',
+ message: expect.stringContaining('wsl --list --verbose')
})
expect(mocks.steps).toEqual(['uname'])
})
diff --git a/src/main/wsl/wsl-orcad-deploy.ts b/src/main/wsl/wsl-orcad-deploy.ts
index 52a1c8bc13a..092fe890263 100644
--- a/src/main/wsl/wsl-orcad-deploy.ts
+++ b/src/main/wsl/wsl-orcad-deploy.ts
@@ -8,7 +8,6 @@ import { recoverInterruptedOrcadActivation } from '../managed-server/activation/
import { readOrcadActivationRecord } from '../managed-server/activation/orcad-activation-record-store'
import { readOrcadActivationTransaction } from '../managed-server/activation/orcad-activation-transaction-store'
import { materializeOrcadArtifact } from '../orcad/orcad-artifact-materializer'
-import { OrcadHostUnsupportedError } from '../orcad/orcad-host-unavailable'
import type { OrcadHostTransport } from '../ssh/orcad-host-transport'
import { ORCAD_ACTIVATION_POLICY_REFUSED_CODE } from '../ssh/orcad-installed-activation'
import { orcadBoundPort } from '../managed-server/lifecycle/orcad-managed-bound-port'
@@ -38,6 +37,7 @@ import { joinRemotePath } from '../ssh/ssh-remote-platform'
import { readLocalFullVersion } from '../managed-server/install/remote-versioned-install'
import { createWslDistroHolder, type WslDistroHolder } from './wsl-distro-holder'
import { wslDistroHolderKey } from './wsl-distro-holder-record'
+import { refuseMissingWslDistro, WslDistroVersion1Error } from './wsl-distro-unsupported'
import { readWslDistroRegistryIdShared } from './wsl-distro-registry-id'
import type { WslOrcadHostTarget } from './wsl-orcad-host-target'
import { createWslOrcadHostTransport, type WslOrcadHostTransport } from './wsl-orcad-host-transport'
@@ -134,12 +134,9 @@ async function launchOverTransport(
const { signal } = options
let ownBuildVersion: string | null = null
const conn = withOwnBuildLaunchEnv(transport, () => ownBuildVersion)
- const kernel = await execCommand(conn, 'uname -r', { signal })
+ const kernel = await execCommand(conn, 'uname -r', { signal }).catch(refuseMissingWslDistro(name))
if (isWsl1KernelRelease(kernel)) {
- throw new OrcadHostUnsupportedError(
- `The WSL 1 distro ${name} isn’t supported by Orca’s server. ` +
- `Convert it with: wsl --set-version ${name} 2`
- )
+ throw new WslDistroVersion1Error(name)
}
// Acquire a holder before launch or WSL can idle-stop orcad's distro.
const holder = options.holder ?? createWslDistroHolder({ userDataPath: userDataPath() })
diff --git a/src/renderer/src/components/settings/WslHostsSection.tsx b/src/renderer/src/components/settings/WslHostsSection.tsx
index aa72b94561b..2141b388ab4 100644
--- a/src/renderer/src/components/settings/WslHostsSection.tsx
+++ b/src/renderer/src/components/settings/WslHostsSection.tsx
@@ -44,6 +44,7 @@ import {
} from '../wsl-move/wsl-move-orchestrator-status'
import { openWslMoveDialogFor } from '../wsl-move/wsl-move-entry'
import { WslMoveUnfinishedNotice } from '../wsl-move/WslMoveUnfinishedNotice'
+import { readIpcErrorDetail } from '@/lib/ipc-error'
function getWslHostRowStatus(
status: WslHostStatus | undefined,
@@ -118,7 +119,8 @@ export function WslHostsSection({
await api.connect({ environmentId, ...(intent ? { intent } : {}) })
onChanged()
} catch (error) {
- toast.error(error instanceof Error ? error.message : String(error))
+ // The main process's message is for the user; Electron's wrapper and the class name aren't.
+ toast.error(readIpcErrorDetail(error) ?? String(error))
} finally {
setConnectingId(null)
}
diff --git a/src/renderer/src/components/sidebar/AddWslHostDialogBody.tsx b/src/renderer/src/components/sidebar/AddWslHostDialogBody.tsx
index 623381811f3..fbcea74ada9 100644
--- a/src/renderer/src/components/sidebar/AddWslHostDialogBody.tsx
+++ b/src/renderer/src/components/sidebar/AddWslHostDialogBody.tsx
@@ -5,6 +5,7 @@ import { useAppStore } from '@/store'
import { AddWslHostFormPanel, canAddWslDistro } from './AddWslHostFormPanel'
import { useWslDistroList } from './use-wsl-distro-list'
import { useWslHostServerFilesMissing } from './use-wsl-hosts-enabled'
+import { readIpcErrorDetail } from '@/lib/ipc-error'
export function AddWslHostDialogBody({
adding,
@@ -64,7 +65,7 @@ export function AddWslHostDialogBody({
)
onAdded()
} catch (cause) {
- setError(cause instanceof Error ? cause.message : String(cause))
+ setError(readIpcErrorDetail(cause) ?? String(cause))
} finally {
onAddingChange(false)
}
diff --git a/src/renderer/src/components/sidebar/AddWslHostFormPanel.test.tsx b/src/renderer/src/components/sidebar/AddWslHostFormPanel.test.tsx
index f43ed0242d7..63bc6368b50 100644
--- a/src/renderer/src/components/sidebar/AddWslHostFormPanel.test.tsx
+++ b/src/renderer/src/components/sidebar/AddWslHostFormPanel.test.tsx
@@ -50,6 +50,11 @@ describe('AddWslHostFormPanel', () => {
expect(html).toContain('until you move them to this host')
})
+ it('spells out the WSL 2 conversion for a WSL 1 distro the list cannot offer', () => {
+ expect(render()).toContain('wsl --set-version Legacy 2')
+ expect(render({ distros: [ubuntu] })).not.toContain('wsl --set-version')
+ })
+
it('says this build cannot run WSL hosts and offers nothing to add', () => {
const html = render({ selectedDistro: 'Ubuntu', serverFilesMissing: true })
expect(html).toContain('This build of Orca can’t run WSL hosts (server files missing).')
diff --git a/src/renderer/src/components/sidebar/AddWslHostFormPanel.tsx b/src/renderer/src/components/sidebar/AddWslHostFormPanel.tsx
index fae5c9a9f4d..7908f739bdd 100644
--- a/src/renderer/src/components/sidebar/AddWslHostFormPanel.tsx
+++ b/src/renderer/src/components/sidebar/AddWslHostFormPanel.tsx
@@ -58,6 +58,8 @@ export function AddWslHostFormPanel({
onCancel: () => void
}): React.JSX.Element {
const selected = distros.find((distro) => distro.name === selectedDistro)
+ // A disabled option can't show its refusal, so the conversion command is spelled out here.
+ const wsl1Distro = distros.find((distro) => distro.version === 1)
const stopped = selected?.state === 'stopped' && canAddWslDistro(selected)
return (
<>
@@ -134,6 +136,15 @@ export function AddWslHostFormPanel({
)}
) : null}
+ {wsl1Distro ? (
+
+ {translate(
+ 'auto.components.sidebar.AddWslHostFormPanel.wsl1Hint',
+ 'WSL 1 distros can’t be hosts. Convert one in a Windows terminal with: wsl --set-version {{value0}} 2',
+ { value0: wsl1Distro.name }
+ )}
+
+ ) : null}
{stopped ? (
{translate(
diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json
index 02a8c84660e..6a33c2f2aab 100644
--- a/src/renderer/src/i18n/locales/en.json
+++ b/src/renderer/src/i18n/locales/en.json
@@ -6573,7 +6573,8 @@
"adding": "Setting up…",
"startAndAdd": "Start and add",
"add": "Add host",
- "refresh": "Refresh"
+ "refresh": "Refresh",
+ "wsl1Hint": "WSL 1 distros can’t be hosts. Convert one in a Windows terminal with: wsl --set-version {{value0}} 2"
},
"wslHostRowStatus": {
"connecting": "Starting",
diff --git a/src/renderer/src/lib/ipc-error.test.ts b/src/renderer/src/lib/ipc-error.test.ts
index 36751451c00..4d2edd2b52e 100644
--- a/src/renderer/src/lib/ipc-error.test.ts
+++ b/src/renderer/src/lib/ipc-error.test.ts
@@ -99,6 +99,15 @@ describe('readIpcErrorDetail', () => {
)
).toBe('SSH connection failed: Relay package not found.')
})
+
+ it("leaves only an unsupported distro's fix for the user", () => {
+ const error = new Error(
+ "Error invoking remote method 'wslHosts:connect': OrcadHostUnsupportedError: Ubuntu-18.04 has glibc 2.27; Orca's WSL host needs 2.28 or newer. Upgrade the distro, or keep this project on Windows."
+ )
+ expect(readIpcErrorDetail(error)).toBe(
+ "Ubuntu-18.04 has glibc 2.27; Orca's WSL host needs 2.28 or newer. Upgrade the distro, or keep this project on Windows."
+ )
+ })
})
// Typed main-process class names must not obscure actionable worktree-removal refusal copy (#19334).
diff --git a/src/shared/wsl-host-types.ts b/src/shared/wsl-host-types.ts
index 277a8360f62..c90da4c3302 100644
--- a/src/shared/wsl-host-types.ts
+++ b/src/shared/wsl-host-types.ts
@@ -68,6 +68,8 @@ export type WslHostServerStop =
export type WslHostAddFailureKind =
| 'unsupported-wsl1'
+ /** Its platform, libc or loader can't run Orca's server (e.g. NixOS, musl without libstdc++). */
+ | 'unsupported-distro'
| 'distro-stopped'
| 'already-added'
| 'ssh-managed'