{"record":{"id":"a927981ac683a2ad","repo":"Eugeny/tabby","slug":"cannot-add-remote-port-forward-before-auth","errorCode":null,"errorMessage":"Cannot add remote port forward before auth","messagePattern":"Cannot add remote port forward before auth","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tabby-ssh/src/session/ssh.ts","lineNumber":818,"sourceCode":"                }).catch(err => {\n                    this.emitServiceMessage(colors.bgRed.black(' X ') + ` Remote has rejected the forwarded connection to ${targetAddress}:${targetPort} via ${fw}: ${err}`)\n                    reject()\n                    throw err\n                }))\n                const socket = accept()\n\n                this.setupSocketChannelEvents(channel, socket, 'Local forward')\n            }).then(() => {\n                this.emitServiceMessage(colors.bgGreen.black(' -> ') + ` Forwarded ${fw}`)\n                this.forwardedPorts.push(fw)\n            }).catch(e => {\n                this.emitServiceMessage(colors.bgRed.black(' X ') + ` Failed to forward port ${fw}: ${e}`)\n                throw e\n            })\n        }\n        if (fw.type === PortForwardType.Remote) {\n            if (!(this.ssh instanceof russh.AuthenticatedSSHClient)) {\n                throw new Error('Cannot add remote port forward before auth')\n            }\n            try {\n                await this.ssh.forwardTCPPort(fw.host, fw.port)\n            } catch (err) {\n                // eslint-disable-next-line @typescript-eslint/no-base-to-string\n                this.emitServiceMessage(colors.bgRed.black(' X ') + ` Remote rejected port forwarding for ${fw}: ${err}`)\n                return\n            }\n            this.emitServiceMessage(colors.bgGreen.black(' <- ') + ` Forwarded ${fw}`)\n            this.forwardedPorts.push(fw)\n        }\n    }\n\n    async removePortForward (fw: ForwardedPort): Promise<void> {\n        if (fw.type === PortForwardType.Local || fw.type === PortForwardType.Dynamic) {\n            fw.stopLocalListener()\n            this.forwardedPorts = this.forwardedPorts.filter(x => x !== fw)\n        }","sourceCodeStart":800,"sourceCodeEnd":836,"githubUrl":"https://github.com/Eugeny/tabby/blob/14e2d60b9b6dee84a53c37f05eefeb803787de04/tabby-ssh/src/session/ssh.ts#L800-L836","documentation":"Thrown by addPortForward() when forwarding type is Remote (server-side -R forward) but this.ssh is not yet an AuthenticatedSSHClient. Remote forwards require the authenticated transport to call forwardTCPPort on the server, so an unauthenticated session cannot set one up.","triggerScenarios":"addPortForward(fw) called with fw.type === PortForwardType.Remote while this.ssh is still a plain russh.SSHClient (pre-auth) or has been disconnected. Can occur if a profile's options.forwardedPorts are applied before auth completes, or if a caller invokes addPortForward manually right after constructing the session.","commonSituations":"Programmatic use that adds a Remote forward before awaiting the session start/auth; a race where addPortForward runs during reconnection before re-auth finishes; profile with remote forwards loaded into a session whose auth subsequently failed but the forward list is still being applied.","solutions":["Ensure the session is fully started and authenticated (await session.start()) before calling addPortForward for a Remote forward.","Gate the call on the instance check: only add the remote forward once this.ssh instanceof russh.AuthenticatedSSHClient.","Configure remote forwards via profile.options.forwardedPorts so they are applied after auth success at ssh.ts:493, not before.","If the session lost auth mid-flight, re-establish it before retrying the forward."],"exampleFix":"// before\nsession.addPortForward(remoteFw) // may run before auth\n// after\nawait session.start()\nif (session.ssh instanceof russh.AuthenticatedSSHClient) {\n    await session.addPortForward(remoteFw)\n}","handlingStrategy":"type-guard","validationCode":"import * as russh from 'russh'\nif (fw.type === PortForwardType.Remote &&\n    !(session.ssh instanceof russh.AuthenticatedSSHClient)) {\n    throw new Error('Wait for SSH auth before adding a remote port forward')\n}","typeGuard":"import * as russh from 'russh'\nfunction isAuthed (s: unknown): s is russh.AuthenticatedSSHClient {\n    return s instanceof russh.AuthenticatedSSHClient\n}","tryCatchPattern":null,"preventionTips":["Await session.start() before adding remote forwards programmatically.","Prefer declaring remote forwards in profile.options.forwardedPorts so they apply post-auth.","Never call addPortForward from a pre-auth or disconnect handler."],"tags":["ssh","port-forwarding","russh","state"],"backgroundTag":null,"analyzedSha":"14e2d60b9b6dee84a53c37f05eefeb803787de04","analyzedAt":"2026-08-12T11:46:48.773Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}