mvanhorn/last30days-skill · error · HtmlPublishError

{status}: {message}

Error message

{status}: {message}

What it means

Raised by publish_html when the HTTP POST to the publish endpoint returns a non-2xx status. The HTTPError body is read and parsed by _error_message(exc.code, detail) into a '{status}: {message}' HtmlPublishError, preserving the provider's own message (e.g. validation failures, wrong password, rate limits). The original HTTPError is chained via 'from exc'.

Source

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

        raise HtmlPublishError("HTML content is empty")

    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

View on GitHub (pinned to c7460f6114)

Solutions

  1. Read the status and provider message: 4xx means fix the request (size, password, payload), 5xx/429 means retry later or with backoff.
  2. If size-related, split or minify the HTML document before publishing.
  3. If auth-related, correct the password parameter or endpoint configuration.
  4. Retry transient failures (429/5xx) with exponential backoff; HtmlPublishError is a single type so branch on the numeric prefix.

Example fix

# before
result = publish_html(html)

# after
try:
    result = publish_html(html)
except HtmlPublishError as e:
    if str(e).startswith(("429", "5")):
        time.sleep(backoff); result = publish_html(html)
    else:
        raise
Defensive patterns

Strategy: retry

Try / catch

import re, time

for attempt in range(3):
    try:
        result = publish_html(html, password=pw)
        break
    except HtmlPublishError as e:
        m = re.match(r"^(\d{3}):", str(e))
        if m and (m.group(1) == "429" or m.group(1).startswith("5")):
            time.sleep(2 ** attempt)
            continue
        raise  # 4xx client errors: fix request, never retry

Prevention

When it happens

Trigger: Uploading an HTML body larger than the endpoint's limit; a wrong or expired 'password' parameter; provider-side 5xx or 429 rate limiting; a custom endpoint= URL that routes to an API that expects a different payload shape.

Common situations: Batch-publishing many documents hits a rate limit; the endpoint changed its API contract after an upgrade; a proxy in front of the endpoint returns 4xx (auth required) with an HTML error page as detail.

Related errors


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