Eugeny/tabby · error · Error
Remote rejected opening a shell channel: ${err}
Error message
Remote rejected opening a shell channel: ${err} What it means
Thrown by SSHShell when `ssh.openShellChannel({ x11 })` rejects - the remote SSH server refused to open an interactive shell channel. The original error is wrapped with a descriptive prefix; if the underlying error mentions X11, the user is additionally hinted to install `xauth` on the remote. Common when the server limits channels, the user has no shell, or pty allocation is denied.
Source
Thrown at tabby-ssh/src/session/shell.ts:48
async start (): Promise<void> {
if (!this.ssh) {
throw new Error('SSH session not set')
}
this.ssh.ref()
this.ssh.willDestroy$.subscribe(() => {
this.destroy()
})
this.logger.debug('Opening shell')
try {
this.shell = await this.ssh.openShellChannel({ x11: this.profile.options.x11 })
} catch (err) {
if (err.toString().includes('Unable to request X11')) {
this.emitServiceMessage(' Make sure `xauth` is installed on the remote side')
}
throw new Error(`Remote rejected opening a shell channel: ${err}`)
}
this.open = true
this.logger.debug('Shell open')
this.loginScriptProcessor?.executeUnconditionalScripts()
this.shell.data$.subscribe(data => {
this.emitOutput(Buffer.from(data))
})
this.shell.eof$.subscribe(() => {
this.logger.info('Shell session ended')
if (this.open) {
this.destroy()
}
})
}View on GitHub (pinned to 14e2d60b9b)
Solutions
- Reduce concurrent sessions on that host or raise server `MaxSessions`/`MaxStartups` if you administer it.
- For an X11-related rejection, install `xauth` on the remote and enable `X11Forwarding yes`, or disable X11 in the profile (`options.x11 = false`).
- Confirm the account has a valid shell (`/bin/bash`, not `/usr/sbin/nologin`) and `PermitTTY yes`.
- Catch the error and retry once for transient transport drops; surface the wrapped remote message to the user for server-side fixes.
Example fix
// before
try { this.shell = await this.ssh.openShellChannel({ x11: this.profile.options.x11 }) }
catch (err) { throw new Error(`Remote rejected opening a shell channel: ${err}`) }
// after - retry without X11 if X11 was the cause
try {
this.shell = await this.ssh.openShellChannel({ x11: this.profile.options.x11 })
} catch (err) {
if (this.profile.options.x11 && err.toString().includes('X11')) {
this.shell = await this.ssh.openShellChannel({ x11: false })
} else throw new Error(`Remote rejected opening a shell channel: ${err}`)
} Defensive patterns
Strategy: retry
Validate before calling
function shouldRequestX11 (profile: SSHProfile, serverSupportsX11: boolean): boolean {
return Boolean(profile.options.x11) && serverSupportsX11
} Try / catch
try {
this.shell = await this.ssh.openShellChannel({ x11: this.profile.options.x11 })
} catch (err) {
const msg = err.toString()
if (this.profile.options.x11 && /X11/i.test(msg)) {
// retry without X11; server denied forwarding
this.shell = await this.ssh.openShellChannel({ x11: false })
} else {
throw new Error(`Remote rejected opening a shell channel: ${err}`)
}
} Prevention
- Disable X11 in the profile if the server does not support it (PermitTTY/X11Forwarding).
- Raise server MaxSessions/MaxStartups if you administer the host and hit limits.
- Confirm the account has a valid shell and PermitTTY yes.
- Retry once for transient transport drops; surface the wrapped remote message to the user.
When it happens
Trigger: Calling `openShellChannel` against a server that rejects channel open: server-side `MaxSessions`/`MaxStartups` exceeded, the account has `nologin`/no shell, pty allocation denied by `sshd_config` (`PermitTTY no`), X11 forwarding requested but `X11Forwarding no` on the server, or the connection dropped mid-handshake.
Common situations: Reached per-user/session limit on a busy bastion; SFTP-only account used for a shell tab; X11 forwarding enabled in the profile but disabled on the server; flaky network caused the transport to die right before channel open.
Related errors
- Config sync host must use HTTPS (got: ${host})
- ${method} ${url} failed: ${response.status} ${response.statu
- Download cancelled
- ${profile.options.host}: jump host "${profile.options.jumpHo
- No private keys in profile
AI-assisted analysis of Eugeny/tabby@14e2d60b9b (2026-08-12).
Data as JSON: /api/errors/c874f702d72fdc68.
Report an issue: GitHub.