stamparm/maltrail · error

alert webhook POST failed

Error message

alert webhook POST failed ('%s')

What it means

Maltrail's webhook alert sender POSTs the alert payload as JSON to ALERT_WEBHOOK_URL via retrieve_content. Any exception from that HTTP call is caught and logged as "alert webhook POST failed (...)"; send then returns False, so no alert is delivered through the webhook channel.

Solutions

  1. Verify ALERT_WEBHOOK_URL is reachable from the sensor host: curl -X POST -H 'Content-Type: application/json' -d '<payload>' $URL.
  2. Check DNS, proxy and firewall settings on the Maltrail host.
  3. Confirm the receiving webhook service is running and returns 2xx for the posted JSON.
  4. Inspect the logged exception text ('%s') for the exact cause (timeout vs connection refused vs HTTP status).

Example fix

# before
ALERT_WEBHOOK_URL = "http://localhost:9999/hook"  # nothing listening

# after
ALERT_WEBHOOK_URL = "https://hooks.example.com/services/xxxx"  # verified with curl
Defensive patterns

Strategy: try-catch

Validate before calling

import urllib.request
try:
    urllib.request.urlopen(urllib.request.Request(config.ALERT_WEBHOOK_URL, data=b'{}', headers={'Content-Type':'application/json'}), timeout=5)
except Exception as ex:
    print('webhook unreachable:', ex)

Type guard

def webhook_configured(cfg):
    return bool(cfg.ALERT_WEBHOOK_URL) and cfg.ALERT_WEBHOOK_URL.startswith(('http://','https://'))

Try / catch

try:
    ok = alert.send(payload)
except Exception:
    ok = False
if not ok:
    fallback_log(payload)  # write alert to disk/queue for replay

Prevention

When it happens

Trigger: The HTTP POST to config.ALERT_WEBHOOK_URL raises: DNS resolution failure, connection refused/timeout, TLS errors, or a non-2xx response raised by retrieve_content. Raised from send, which is invoked by process for each filtered log line.

Common situations: Webhook URL typo'd or pointing at a service that is down; local Slack/Mattermost relay unreachable; firewall or proxy blocking outbound HTTPS from the Maltrail host; the endpoint requiring auth headers Maltrail does not send.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13). Data as JSON: /api/errors/5a3c5e259f72fba4. Report an issue: GitHub.

Appendix: source

Thrown at core/alert.py:161

    from collections import OrderedDict
    return json.dumps(OrderedDict((key, event.get(key, "")) for key in
                                  ("timestamp", "sensor", "severity", "src_ip", "src_port", "dst_ip",
                                   "dst_port", "proto", "type", "trail", "info", "reference")))


def send(event):
    """POST one event. Never raises: a webhook outage must not stop the server or the tailer."""

    payload = body(event)
    if payload is None:
        return False

    try:
        retrieve_content(config.ALERT_WEBHOOK_URL, data=payload.encode(UNICODE_ENCODING),
                         headers={"Content-Type": "application/json"})
        return True
    except Exception as ex:
        log_error("alert webhook POST failed ('%s')" % ex, single=True)
        return False


def process(line):
    """Filter, throttle and send one log line. Returns True when a message went out."""

    event = parse_event_line(line)
    if event is None or not wanted(event) or throttled(event):
        return False
    return send(event)


def _log_path(sec=None):
    localtime = time.localtime(time.time() if sec is None else sec)
    return os.path.join(config.LOG_DIR, "%d-%02d-%02d.log" % (localtime.tm_year, localtime.tm_mon, localtime.tm_mday))


def _tail_once(state):

View on GitHub (pinned to 77cfb06d76)