can1357/oh-my-pi · error
ssh://: user/port overrides are not allowed for the configur
Error message
ssh://: user/port overrides are not allowed for the configured host "${decodedBareHost}"; use ssh://${bareHost}/<path> or an unconfigured hostname What it means
A literal user or port in an ssh:// URL is treated as an authority override on an OpenSSH destination. But a host name that matches a configured ssh.json entry is addressed only by its name — overrides would bypass the stored key/port settings and defeat the ControlMaster cache, which keys on the host name, so the handler rejects the combination.
Source
Thrown at packages/coding-agent/src/internal-urls/ssh-protocol.ts:224
// where `url.password === ""`). `rawHost` keeps the literal marker, so it differs
// from the canonical decoded `[user@]host[:port]` WHATWG actually parsed. Every
// valid authority — including percent-encoded reserved-char aliases — reconstructs
// to exactly `rawHost`, so only malformed userinfo trips this.
const canonicalAuthority = `${url.username ? `${decodeOr(url.username)}@` : ""}${decodeOr(bareHost)}${port !== undefined ? `:${port}` : ""}`;
if (url.rawHost !== canonicalAuthority) {
throw new Error(
`ssh://: unsupported or malformed authority in "${url.href}"; use ssh://[user@]host[:1-65535]/<absolute-path>`,
);
}
const items = await loadConfiguredHosts(cwd);
// A literal user/port in the URL is an authority override. A configured alias
// is addressed only by its (percent-encoded) name, never with a separate
// user/port — so reject an override on a configured bare name, else opaque.
if (username || port !== undefined) {
const decodedBareHost = decodeOr(bareHost);
if (items.some(entry => entry.name === bareHost || entry.name === decodedBareHost)) {
throw new Error(
`ssh://: user/port overrides are not allowed for the configured host "${decodedBareHost}"; use ssh://${bareHost}/<path> or an unconfigured hostname`,
);
}
const sshUser = username ? decodeOr(username) : undefined;
const sshTargetHost = decodeOr(sshHost);
const name = `${sshUser ? `${sshUser}@` : ""}${sshTargetHost}${port !== undefined ? `:${port}` : ""}`;
return { name, host: sshTargetHost, username: sshUser, port };
}
// No explicit user/port: match the full decoded authority against a
// configured name (so an encoded reserved-char alias resolves correctly).
const match = items.find(entry => entry.name === rawAuthority) ?? items.find(entry => entry.name === bareHost);
if (match) {
return {
name: match.name,
host: match.host,
username: match.username,
port: match.port,View on GitHub (pinned to 9690622007)
Solutions
- Address the configured host by name only: `ssh://prod/path` — its user/port come from the ssh.json entry
- Update the ssh.json entry if you need different user/port/key settings for that host
- Use a real (unconfigured) hostname with user/port for a one-off override connection
Example fix
// before
resolve('ssh://root@prod/etc/hosts') // 'prod' is a configured alias
// after
resolve('ssh://prod/etc/hosts') // or edit prod's ssh.json entry Defensive patterns
Strategy: validation
Validate before calling
const configured = new Set((await capability.loadCapability<SSHHost>('ssh', { cwd })).items.flatMap(h => [h.name, decodeURIComponent(h.name)]));
const u = new URL(candidate);
if (u.protocol === 'ssh:' && (u.username || u.port) && configured.has(u.hostname)) throw new Error(`'${u.hostname}' is configured; address it by name without user/port overrides`); Type guard
function isPlainConfiguredHost(u: URL, configured: Set<string>): boolean { return !(u.username || u.port) || !configured.has(u.hostname); } Try / catch
try {
const res = await handler.resolve(url, ctx);
} catch (e) {
if (e instanceof Error && e.message.includes('user/port overrides are not allowed')) {
// drop user/port and use the alias, or edit the ssh.json entry, then retry
} else throw e;
} Prevention
- Treat configured ssh.json names as opaque aliases — no user@ or :port on them
- Change user/port/key in the ssh.json entry rather than overriding per-URL
- Use raw hostnames (not configured names) when you need ad-hoc overrides
When it happens
Trigger: Resolving e.g. `ssh://root@prod/path` or `ssh://prod:2222/path` where `prod` is the `name` of an entry in the ssh.json capability file (matched against either the raw or decoded bare host).
Common situations: Trying to connect to a configured alias as a different user; assuming the alias can be parameterized with :port; forgetting that configured hosts carry their own username/port/key settings.
Related errors
- imageUrls exposure "ssh" requires imageUrls.publicBaseUrl
- imageUrls exposure "ssh" requires imageUrls.sshTarget
- No known OAuth callback port for '${provider}'. Use device-c
- SSH key not found: ${keyPath}
- SSH key is not a file: ${keyPath}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/df531c90107fee6b.
Report an issue: GitHub.