{"record":{"id":"9918dbb087ae1a4d","repo":"HKUDS/nanobot","slug":"error","errorCode":null,"errorMessage":"{error}","messagePattern":"\\{error\\}","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"nanobot/channels/validation.py","lineNumber":367,"sourceCode":"    return cast(dict[str, Any], data) if isinstance(data, dict) else {}\n\n\ndef _http_post(url: str, *, headers: dict[str, str] | None = None) -> dict[str, Any]:\n    with httpx.Client(timeout=_TIMEOUT_SECONDS) as client:\n        response = client.post(url, headers=headers)\n        response.raise_for_status()\n        data = response.json()\n    return cast(dict[str, Any], data) if isinstance(data, dict) else {}\n\n\ndef _probe_tcp(host: str, port: int, *, allow_loopback: bool = False) -> None:\n    url_host = host if \":\" not in host or host.startswith(\"[\") else f\"[{host}]\"\n    ok, error, resolved_ips = resolve_url_target(\n        f\"http://{url_host}:{port}/\",\n        allow_loopback=allow_loopback,\n    )\n    if not ok:\n        raise ValueError(error)\n\n    context = ssl.create_default_context()\n    last_error: OSError | None = None\n    for target_ip in resolved_ips:\n        try:\n            with socket.create_connection((target_ip, port), timeout=_TIMEOUT_SECONDS) as sock:\n                if port in {465, 993, 995}:\n                    with context.wrap_socket(sock, server_hostname=host.strip(\"[]\")):\n                        return\n                return\n        except OSError as exc:\n            last_error = exc\n    if last_error is not None:\n        raise last_error\n    raise OSError(f\"Could not resolve {host}\")\n\n\n# Public helpers for channel-owned validators. Keeping response shaping here lets","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/HKUDS/nanobot/blob/42f37dc4c0e409eac7818a82d165c5f2757bc075/nanobot/channels/validation.py#L349-L385","documentation":"In _probe_tcp(), the pre-connection target check failed: resolve_url_target() returned ok=False with an error string, which is re-raised verbatim as ValueError. This is a generic guard raising another resolver's message; the input at fault is the host/port combination whose DNS resolution or SSRF policy check failed (e.g. resolves to loopback/private IP while allow_loopback is False).","triggerScenarios":"Thrown at nanobot/channels/validation.py:367 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use a resolvable, policy-compliant host for the channel being validated","Pass allow_loopback=True only when a loopback target is intentional (local testing)","Read the embedded resolver message to see whether it was DNS failure or an SSRF policy rejection"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"42f37dc4c0e409eac7818a82d165c5f2757bc075","analyzedAt":"2026-08-26T00:18:52.276Z","contentChangedAt":"2026-08-26T00:18:52.276Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}