deepseek-ai/deepseek-harness · error
client-connection: trustedHosts entry ${JSON.stringify(entry
Error message
client-connection: trustedHosts entry ${JSON.stringify(entry)} is not a bare host[:port] authority What it means
assertTrustedAuthority backs the client-connection trust fence against DNS rebinding and cross-site requests. Each trustedHosts entry must be a bare host or host:port authority whose canonical WHATWG URL parse equals the entry itself (case aside), so anything parsing would silently rewrite — schemes, paths, userinfo, whitespace, dangling or zero-padded ports, and non-canonical host spellings (hex IPs, percent-encoding, unbracketed IPv6, non-punycode IDN) — fails the plugin load instead of quietly broadening the grant.
Source
Thrown at packages/client/connection/src/api-request-trust.ts:57
/**
* Assert one configured `trustedHosts` entry is a bare authority (`host` or
* `host:port`) in canonical form: it must survive WHATWG parsing unchanged
* (case aside). Anything parsing would silently rewrite is refused as a typo
* that must fail the load loudly instead of being ignored until requests 403
* or quietly changing the grant: URL parts beyond the authority
* (`harness.internal/path`, `user@harness.internal` — which would authorize
* the embedded hostname), stripped whitespace, a dangling colon or
* zero-padded port (which would broaden an intended exact-port grant to every
* port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding,
* unbracketed IPv6; IDN hosts are declared in punycode, the form the wire
* carries).
* @param entry - the configured value, verbatim.
*/
export function assertTrustedAuthority(entry: string): void {
const entryUrl = parseAuthority(entry)
if (entryUrl !== undefined && canonicalAuthority(entry, entryUrl) === entry.toLowerCase()) return
throw new Error(`client-connection: trustedHosts entry ${JSON.stringify(entry)} is not a bare host[:port] authority`)
}
/**
* Canonical form of a parsed authority: `hostname` when no port was written,
* else `hostname:port`. The port is judged from URL parses under both special
* schemes (their default ports differ, so `:80` and `:443` still count as
* explicit), never from the raw string, where WHATWG trimming would misread
* shapes like `host:port ` as port-less.
*/
function canonicalAuthority(entry: string, entryUrl: URL): string {
// An authority that parsed under http cannot fail under https.
const port = entryUrl.port !== '' ? entryUrl.port : new URL(`https://${entry}`).port
return port === '' ? entryUrl.hostname : `${entryUrl.hostname}:${port}`
}
/**
* Whether the request authority matches a `trustedHosts` entry. An entry with
* an explicit port matches that exact authority; a port-less entry matches theView on GitHub (pinned to b150a551b8)
Solutions
- Write entries as bare lowercase host or host:port — harness.example.com:8080, 192.168.1.10
- Encode IDN names in punycode (xn--mnchen-3ya.example) and bracket IPv6 literals ([::1])
- Drop schemes, paths, userinfo, surrounding whitespace, and leading zeros in ports; a port-less entry matches every port on that host
Example fix
# before
client-connection:
trustedHosts:
- https://harness.example.com:8080/
- MÜNCHEN.example
- 0x7f.0.0.1
# after
client-connection:
trustedHosts:
- harness.example.com:8080
- xn--mnchen-3ya.example
- 127.0.0.1 Defensive patterns
Strategy: validation
Validate before calling
// Validate entries with the shipped guard before the plugin loads:
import { assertTrustedAuthority } from '@deepseek-ai/dsh-client-connection'
for (const entry of config.trustedHosts ?? []) assertTrustedAuthority(entry) Type guard
function isBareAuthority(entry: string): boolean {
try {
const u = new URL(`http://${entry}`)
const port = u.port !== '' ? u.port : new URL(`https://${entry}`).port
const canonical = port === '' ? u.hostname : `${u.hostname}:${port}`
return canonical === entry.toLowerCase()
} catch {
return false
}
} Prevention
- Never paste full origins into trustedHosts; authorities only
- Keep entries lowercase and canonical, and run them through assertTrustedAuthority as a config preflight
- Prefer LAN IP literals, which the dsh CLI derives itself, over hand-written hostnames
When it happens
Trigger: Loading the client-connection plugin with trustedHosts values such as https://host:8080, host.internal/path, user@host.internal, host:08080, host:, 0x7f.0.0.1, an unbracketed IPv6 literal, or a unicode IDN name.
Common situations: Pasting a full origin URL from the browser into cordis.yml; writing an IDN domain in unicode instead of punycode; leaving a trailing slash or colon; unbracketed IPv6 literals.
Related errors
- dsh-code-runtime-worker-thread: config.${key} must be a posi
- ${name}: retainRatio (${retention.retainRatio}) must be less
- attachment-local: imageCompressionConcurrency must be an int
- client-connection maxRequestBodyBytes (${String(maxRequestBo
- permission settings has no defaultPreset value
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/238e29b388021613.
Report an issue: GitHub.