{"record":{"id":"17155bc31a34c238","repo":"Eugeny/tabby","slug":"profile-options-host-jump-host-profile-opti","errorCode":null,"errorMessage":"${profile.options.host}: jump host \"${profile.options.jumpHost}\" not found in your config","messagePattern":"(.+?): jump host \"(.+?)\" not found in your config","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tabby-ssh/src/components/sshTab.component.ts","lineNumber":85,"sourceCode":"                case 'open-sftp':\n                    this.openSFTP()\n                    break\n            }\n        })\n\n        super.ngOnInit()\n    }\n\n    async setupOneSession (injector: Injector, profile: SSHProfile, multiplex = true): Promise<SSHSession> {\n        let session = await this.sshMultiplexer.getSession(profile)\n        if (!multiplex || !session || !profile.options.reuseSession) {\n            session = new SSHSession(injector, profile)\n\n            if (profile.options.jumpHost) {\n                const jumpConnection = (await this.profilesService.getProfiles()).find(x => x.id === profile.options.jumpHost)\n\n                if (!jumpConnection) {\n                    throw new Error(`${profile.options.host}: jump host \"${profile.options.jumpHost}\" not found in your config`)\n                }\n\n                const jumpSession = await this.setupOneSession(\n                    this.injector,\n                    this.profilesService.getConfigProxyForProfile<SSHProfile>(jumpConnection),\n                )\n\n                jumpSession.ref()\n                session.willDestroy$.subscribe(() => jumpSession.unref())\n                jumpSession.willDestroy$.subscribe(() => {\n                    if (session?.open) {\n                        session.destroy()\n                    }\n                })\n\n                if (!(jumpSession.ssh instanceof russh.AuthenticatedSSHClient)) {\n                    throw new Error('Jump session is not authenticated yet somehow')\n                }","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/Eugeny/tabby/blob/14e2d60b9b6dee84a53c37f05eefeb803787de04/tabby-ssh/src/components/sshTab.component.ts#L67-L103","documentation":"Thrown during SSH session setup when `profile.options.jumpHost` references a profile id that is not present in the loaded profiles list. The jump host is resolved by id (`profiles.find(x => x.id === jumpHost)`); a missing id means the proxy chain cannot be constructed, so connection is aborted before any socket is opened.","triggerScenarios":"An SSH profile has `options.jumpHost = '<id>'` but no profile with that id exists in config. Occurs after the jump-host profile was deleted/renamed, after a config-sync that omitted it, or when the id was typed manually and is wrong.","commonSituations":"User deleted or renamed the jump/bastion profile but left references to it; config imported from another machine without the jump host; typo in the id; profile id changed after a migration.","solutions":["Open the profile settings and re-pick the jump host from the dropdown so the correct id is stored, or clear the jumpHost field.","If the jump host profile was deleted, recreate it and re-select it, or remove the jumpHost reference.","Validate profile integrity at config load: scan for jumpHost ids that no longer resolve and warn the user.","Check that config-sync delivered the complete set of profiles (the jump host must be synced alongside its dependents)."],"exampleFix":"// before\nif (!jumpConnection) throw new Error(`${profile.options.host}: jump host \"${profile.options.jumpHost}\" not found in your config`)\n\n// after - validate references at config load and surface a list of candidates\nconst all = await this.profilesService.getProfiles()\nconst jumpConnection = all.find(x => x.id === profile.options.jumpHost)\nif (!jumpConnection) {\n    const suggestions = all.filter(x => (x.options as any)?.host === profile.options.host).map(x => x.id)\n    throw new Error(`Jump host id \"${profile.options.jumpHost}\" not found. Did you mean: ${suggestions.join(', ') || '(no candidates)'}`)\n}","handlingStrategy":"validation","validationCode":"async function jumpHostExists (profilesService: ProfilesService, jumpId: string | undefined): Promise<boolean> {\n    if (!jumpId) return true\n    const all = await profilesService.getProfiles()\n    return all.some(p => p.id === jumpId)\n}\n\nif (!await jumpHostExists(this.profilesService, profile.options.jumpHost)) {\n    throw new Error(`Jump host ${profile.options.jumpHost} not found; pick a valid profile or clear it`)\n}","typeGuard":"function hasValidJumpHost (profile: SSHProfile, all: Profile[]): boolean {\n    return !profile.options.jumpHost || all.some(p => p.id === profile.options.jumpHost)\n}","tryCatchPattern":"try {\n    session = await this.setupOneSession(injector, profile)\n} catch (e) {\n    if (e instanceof Error && /jump host .* not found/.test(e.message)) {\n        // prompt user to re-pick or clear jumpHost, then retry\n        return\n    }\n    throw e\n}","preventionTips":["Validate jumpHost references at config load and warn about dangling ids.","Re-create deleted jump-host profiles or clear the reference before connecting.","Sync the full profile set so jump hosts travel with their dependents.","Use the profile picker UI (not manual id entry) to set jumpHost to avoid typos."],"tags":["ssh","jump-host","profiles","configuration","references"],"backgroundTag":null,"analyzedSha":"14e2d60b9b6dee84a53c37f05eefeb803787de04","analyzedAt":"2026-08-12T11:46:48.773Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}