{"record":{"id":"c2b15f78d3299834","repo":"windmill-labs/windmill","slug":"no-pinned-address-to-connect","errorCode":null,"errorMessage":"no pinned address to connect","messagePattern":"no pinned address to connect","errorType":"exception","errorClass":"std::io::Error (AddrNotAvailable)","httpStatus":null,"severity":"error","filePath":"backend/windmill-trigger-websocket/src/proxy.rs","lineNumber":113,"sourceCode":"    // Direct connection. Nothing to pin (IP literal or SSRF guard opted out):\n    // preserve the original resolve-and-connect path.\n    if pinned_addrs.is_empty() {\n        return connect_async(request).await;\n    }\n\n    // Pin to a validated address so this connect targets the same IP the SSRF\n    // guard checked. Try each in order (e.g. IPv6 then IPv4) until one connects.\n    let mut last_err: Option<io::Error> = None;\n    for addr in pinned_addrs {\n        match TcpStream::connect(addr).await {\n            Ok(socket) => {\n                return client_async_tls_with_config(request, socket, None, None).await;\n            }\n            Err(e) => last_err = Some(e),\n        }\n    }\n    Err(WsError::Io(last_err.unwrap_or_else(|| {\n        io::Error::new(\n            io::ErrorKind::AddrNotAvailable,\n            \"no pinned address to connect\",\n        )\n    })))\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct ProxyTarget {\n    host: String,\n    port: u16,\n    /// Base64-encoded `user:pass` from URL userinfo, ready to drop into\n    /// the `Proxy-Authorization: Basic …` header value.\n    basic_auth: Option<String>,\n}\n\n/// Resolve the proxy URL string to use for outbound `(scheme, host)`.\n///\n/// `wss://`/`https://` reads `HTTPS_PROXY`, `ws://`/`http://` reads","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-trigger-websocket/src/proxy.rs#L95-L131","documentation":"`connect_async_with_proxy` iterates over resolved candidate addresses (e.g. from DNS or a pinned proxy address) attempting a connection each time. This error is the fallback produced when the candidate list was empty or every attempt failed without recording a specific error, so there is no underlying `last_err` to surface. It wraps an `io::Error` with `ErrorKind::AddrNotAvailable` inside the crate's `WsError::Io` variant.","triggerScenarios":"Calling `connect_async_with_proxy` (via `test_connection` or `get_consumer`) when no address candidates exist to try — e.g. the pinned proxy/socket address list is empty after DNS resolution returns nothing, or all attempts failed before setting `last_err`.","commonSituations":"Proxy host configured as an empty or unresolvable hostname; DNS outage in a container/K8s cluster; misconfigured `WINDMILL_TRIGGER_WS` proxy env vars; IPv6-only or IPv4-only environments where resolution yields no usable A/AAAA records.","solutions":["Verify the proxy/WebSocket host resolves: run `getent hosts <host>` (or `nslookup`) inside the same network/container as the worker","Check the proxy configuration (env/config file) for a typos, empty host, or wrong scheme in the proxy URL","If behind corporate DNS, ensure the resolver is reachable from the worker container (check /etc/resolv.conf)","Retry after fixing DNS/connectivity; the error is produced at connect time and is transient if DNS was down"],"exampleFix":"// before\nlet proxy = std::env::var(\"WS_PROXY\").ok(); // may be Some(\"\") -> no candidates\n// after\nlet proxy = match std::env::var(\"WS_PROXY\") {\n    Ok(v) if !v.trim().is_empty() => Some(v),\n    _ => None,\n};","handlingStrategy":"retry","validationCode":"// resolve the host before connecting\nlet host = proxy_host_from_config();\nlet resolved = tokio::net::lookup_host((host.as_str(), 443u16))\n    .await\n    .expect(\"proxy host must resolve\");\nif resolved.into_iter().next().is_none() {\n    return Err(anyhow!(\"proxy host {host} resolved to no addresses\"));\n}","typeGuard":null,"tryCatchPattern":"match connect_async_with_proxy(&url, &proxy).await {\n    Err(WsError::Io(e)) if e.kind() == std::io::ErrorKind::AddrNotAvailable => {\n        tracing::warn!(\"no address candidates for proxy, retrying: {e}\");\n        // exponential backoff / fix DNS config then retry\n    }\n    Err(e) => return Err(e.into()),\n    Ok(_) => {}\n}","preventionTips":["Validate proxy URLs at startup (non-empty host, correct scheme) and fail fast on bad config","Monitor DNS health in the worker's network (alert on lookup failures)","Use IPs or a reliable internal DNS for pinned proxy addresses","Log every candidate address attempted so empty lists are visible in diagnostics"],"tags":["network","websocket","dns","proxy"],"backgroundTag":"address-not-available","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}