mvanhorn/last30days-skill · error · HtmlPublishError

{exc.reason}

Error message

{exc.reason}

What it means

Raised by publish_html when the request fails before getting an HTTP response and the underlying exception is a urllib URLError — the message is str(exc.reason), the inner cause (DNS failure, connection refused, SSL error, timeout during connect). Chained as 'from exc' so the full traceback still shows the URLError.

Source

Thrown at skills/last30days/scripts/lib/html_publish.py:57

    payload: dict[str, str] = {"html_content": html_content}
    if password is not None:
        payload["password"] = password

    request = Request(
        endpoint,
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json", "Accept": "application/json"},
        method="POST",
    )
    open_fn = opener or urlopen
    try:
        with open_fn(request, timeout=timeout) as response:
            body = response.read().decode("utf-8")
    except HTTPError as exc:
        detail = exc.read().decode("utf-8", errors="replace")
        raise HtmlPublishError(_error_message(exc.code, detail)) from exc
    except URLError as exc:
        raise HtmlPublishError(str(exc.reason)) from exc
    except OSError as exc:
        raise HtmlPublishError(str(exc)) from exc

    try:
        result = json.loads(body)
    except json.JSONDecodeError as exc:
        raise HtmlPublishError("publish endpoint returned non-JSON response") from exc
    if not isinstance(result, dict):
        raise HtmlPublishError("publish endpoint returned unexpected JSON response")

    url = result.get("url")
    if not isinstance(url, str) or not url.startswith("https://"):
        raise HtmlPublishError("publish endpoint response did not include a valid url")
    return result


def publish_html_documents(
    documents: Mapping[str, str],

View on GitHub (pinned to c7460f6114)

Solutions

  1. Verify basic connectivity: curl -I https://api.ht-ml.app/v1/sites (or your custom endpoint).
  2. For custom endpoints, confirm the local/remote server is up and the URL scheme/port are right.
  3. In proxied environments, export HTTPS_PROXY and ensure the proxy CA is trusted.
  4. Treat as transient only if the network is flaky; DNS/connection-refused usually means environment, not provider.

Example fix

# before
result = publish_html(html)

# after
import socket
try:
    result = publish_html(html)
except HtmlPublishError as e:
    if isinstance(e.__cause__, URLError) and isinstance(e.__cause__.reason, (socket.gaierror, ConnectionRefusedError)):
        log.warning("endpoint unreachable: %s", e)
        result = None
Defensive patterns

Strategy: retry

Validate before calling

import socket

def endpoint_reachable(host: str, port: int = 443, timeout: float = 5.0) -> bool:
    try:
        socket.create_connection((host, port), timeout=timeout).close()
        return True
    except OSError:
        return False

Try / catch

from urllib.error import URLError

try:
    publish_html(html)
except HtmlPublishError as e:
    if isinstance(e.__cause__, URLError):
        reason = e.__cause__.reason
        # DNS failure / refused / SSL -> environment problem; fix network, do not blind-retry
        log.error("publish endpoint unreachable: %s", reason)

Prevention

When it happens

Trigger: No network / offline machine; DNS cannot resolve api.ht-ml.app (or the custom endpoint host); a firewall or proxy blocks outbound HTTPS; TLS certificate verification fails; endpoint port closed.

Common situations: Running inside a container or CI runner without network egress; corporate MITM proxy with an untrusted CA; airplane-mode laptop; a custom endpoint= pointing at a local server that is not running yet (connection refused).

Related errors


AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15). Data as JSON: /api/errors/2926cc8915d20f1a. Report an issue: GitHub.