{"record":{"id":"d6674a9e27be8433","repo":"ZhuLinsen/daily_stock_analysis","slug":"futu-api-10-8-6808-ipv4-futu-opend-host","errorCode":null,"errorMessage":"futu-api==10.8.6808 的网络层仅支持 IPv4；FUTU_OPEND_HOST 当前为 {host!r}，请改用 IPv4 地址或可解析到 IPv4 的主机名。","messagePattern":"futu-api==10\\.8\\.6808 的网络层仅支持 IPv4；FUTU_OPEND_HOST 当前为 (.+?)，请改用 IPv4 地址或可解析到 IPv4 的主机名。","errorType":"exception","errorClass":"FutuPortfolioError","httpStatus":null,"severity":"error","filePath":"src/brokers/futu/portfolio.py","lineNumber":133,"sourceCode":"def _connection_settings() -> tuple[str, int]:\n    \"\"\"Return the validated IPv4 OpenD host and port from environment settings.\"\"\"\n\n    host = (os.getenv(\"FUTU_OPEND_HOST\") or \"127.0.0.1\").strip()\n    raw_port = (os.getenv(\"FUTU_OPEND_PORT\") or \"11111\").strip()\n    try:\n        port = int(raw_port)\n    except ValueError as exc:\n        raise FutuPortfolioError(f\"FUTU_OPEND_PORT 不是有效端口: {raw_port!r}\") from exc\n    if not host or not 1 <= port <= 65535:\n        raise FutuPortfolioError(f\"Futu OpenD 地址无效: {host!r}:{port}\")\n\n    address_text = host[1:-1] if host.startswith(\"[\") and host.endswith(\"]\") else host\n    try:\n        address = ipaddress.ip_address(address_text)\n    except ValueError:\n        address = None\n    if address is not None and address.version != 4:\n        raise FutuPortfolioError(\n            \"futu-api==10.8.6808 的网络层仅支持 IPv4；\"\n            f\"FUTU_OPEND_HOST 当前为 {host!r}，请改用 IPv4 地址或可解析到 IPv4 的主机名。\"\n        )\n    return host, port\n\n\ndef _configured_account_id() -> Optional[int]:\n    \"\"\"Return the optional configured real account ID.\"\"\"\n\n    value = (os.getenv(\"FUTU_ACC_ID\") or \"\").strip()\n    if not value:\n        return None\n    try:\n        account_id = int(value)\n    except ValueError as exc:\n        raise FutuPortfolioError(\"FUTU_ACC_ID 必须是正整数账户 ID\") from exc\n    if account_id <= 0:\n        raise FutuPortfolioError(\"FUTU_ACC_ID 必须是正整数账户 ID\")","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/brokers/futu/portfolio.py#L115-L151","documentation":"FutuPortfolioError raised in _connection_settings (src/brokers/futu/portfolio.py:133) when FUTU_OPEND_HOST resolves (via ipaddress.ip_address) to an IPv6 literal. The pinned futu-api==10.8.6808 network layer only supports IPv4, so the guard rejects IPv6 addresses up front (including bracketed [::1] form, which is unbracketed before parsing) with a message telling you to use an IPv4 address or an IPv4-resolvable hostname.","triggerScenarios":"Setting FUTU_OPEND_HOST=::1 or [::1] to reach a local OpenD; entering an IPv6 LAN address like fe80::1 when OpenD listens on IPv6; systems where localhost preferentially resolves to ::1 — note hostnames are NOT rejected here, only literals, so 'localhost' passes but must resolve to IPv4 at connect time.","commonSituations":"Modern hosts where 127.0.0.1 is replaced with ::1 out of habit; IPv6-only Docker networks; remote OpenD reached over a tunnel that yields IPv6 addresses.","solutions":["Set FUTU_OPEND_HOST to an IPv4 literal: 127.0.0.1 for local, or the server's IPv4 address for remote.","If using a hostname, make sure it resolves to an A record (IPv4) — check with 'dig <host> A' or 'ping <host>' — since the SDK will connect over IPv4 only.","If OpenD is only listening on IPv6, reconfigure OpenD to bind an IPv4 address (its own config), or front it with an IPv4 proxy/port-forward (e.g. socat) and point FUTU_OPEND_HOST at that.","Ensure any ssh tunnel/port-forward you use terminates on an IPv4 bind address."],"exampleFix":"# before (.env)\nFUTU_OPEND_HOST=::1\n\n# after (.env)\nFUTU_OPEND_HOST=127.0.0.1","handlingStrategy":"validation","validationCode":"import ipaddress\n\ndef opend_host_is_ipv4(host: str) -> bool:\n    text = host[1:-1] if host.startswith('[') and host.endswith(']') else host\n    try:\n        return ipaddress.ip_address(text).version == 4\n    except ValueError:\n        return True  # hostname: resolution checked at connect time","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer IPv4 literals (127.0.0.1, LAN IPv4) for FUTU_OPEND_HOST with futu-api 10.8.6808.","If using hostnames, verify an A record exists (dig <host> A).","Configure port-forwards/tunnels with IPv4 bind addresses."],"tags":["futu","configuration","ipv6","network"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}