siyuan-note/siyuan · error

failed to resolve host:

Error message

failed to resolve host: 

What it means

CheckHostSSRF performs DNS resolution of the target host before any outbound agent request (web_fetch, http_request, generated-image download, skill source download) to block SSRF (see GHSA-rg26-cg95-gq6p). If the host cannot be resolved at all, the request is rejected with this error carrying the DNS failure reason.

Solutions

  1. Verify the hostname spelling and that it resolves: nslookup <host> or dig <host>
  2. Check network/DNS configuration (resolv.conf, VPN, proxy) and connectivity
  3. Use a fully-qualified public domain; internal hosts are intentionally blocked by the SSRF guard
  4. If DNS is flaky, retry after connectivity is restored — never bypass the check

Example fix

// before
fetchPost("/api/ai/webFetch", {url: "http://intranet-host/data"})
// after
fetchPost("/api/ai/webFetch", {url: "https://example.com/data"})
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight in the caller
if net.ParseIP(host) == nil {
    if _, err := net.LookupHost(host); err != nil { /* fail fast: unresolvable host */ }
}

Try / catch

if strings.HasPrefix(err.Error(), "failed to resolve host") {
    // surface a DNS/network problem to the user; do not retry in a tight loop
}

Prevention

When it happens

Trigger: HTTPRequest, WebFetch, downloadGeneratedImage, or downloadSkillSource is called with a hostname DNS cannot resolve — a typo'd domain, expired domain, no network/DNS server, or an intranet-only name resolvable only inside a private network.

Common situations: Offline machine or broken DNS configuration; a misspelled URL in an AI agent tool call; a hostname valid only on an internal network that the SSRF guard intentionally cannot reach; IPv6-only environments with broken AAAA resolution.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/836b5c703117c5ba. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/httprequest.go:52

	"time"

	"github.com/siyuan-note/httpclient"
	golangProxy "golang.org/x/net/proxy"
)

const (
	maxHTTPRequestBytes     = 5 * 1024 * 1024  // text/html、text/plain、application/json 等文本类响应上限
	maxHTTPRequestFileBytes = 10 * 1024 * 1024 // 二进制响应落盘上限
	maxHTTPRequestChars     = 50000
)

// CheckHostSSRF 校验主机名解析出的 IP 不落在内网/回环等不可达地址段,
// 防止智能体被诱导发起 SSRF 攻击。web_fetch 与 http_request 共用此校验。
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rg26-cg95-gq6p
func CheckHostSSRF(host string) error {
	ips, err := net.LookupIP(host)
	if err != nil {
		return errors.New("failed to resolve host: " + err.Error())
	}
	for _, ip := range ips {
		// 与 SSRFSafeDialer 共用 isPrivateIP,覆盖 NAT64、6to4、Teredo 等 IPv6 过渡地址。
		if isPrivateIP(ip) {
			return errors.New("access to private/internal IP is prohibited")
		}
	}
	return nil
}

// ssrfSafeClient 是智能体出站请求专用的 HTTP 客户端:直连时将目标固定到已校验的公网 IP,
// 使用代理时则先与用户配置的代理建立隧道,再通过隧道连接固定后的目标 IP,同时保留原始 Host 和 TLS SNI。
// 两种方式都不会在校验后再次按目标域名解析,避免 DNS 重绑定 TOCTOU 绕过。
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-x8gv-g2g3-65fj
var ssrfSafeClient = newSSRFSafeClient()

func newSSRFSafeClient() *http.Client {
	return newSSRFSafeClientWithResolver(net.DefaultResolver.LookupIPAddr)

View on GitHub (pinned to 9f775e8a12)