{"record":{"id":"4c2d938bc179c56c","repo":"zed-industries/zed","slug":"slack-webhook-returned-response-status-code-re","errorCode":null,"errorMessage":"Slack webhook returned {response.status_code}: {response.text[:200]}","messagePattern":"Slack webhook returned (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"script/github-guild-board.py","lineNumber":411,"sourceCode":"    # without every caller having to remember to do it.\n    return f\"<{url}|{escape_slack(text)}>\"\n\n\ndef send_slack(text):\n    webhook = os.environ.get(\"SLACK_WEBHOOK_GUILD_INTERNAL\")\n    if not webhook:\n        raise RuntimeError(\"SLACK_WEBHOOK_GUILD_INTERNAL is not set\")\n    message = f\"{random.choice(ZEDGAR_QUIPS)} {text}\"\n    response = requests.post(\n        webhook,\n        json={\n            \"text\": message,\n            \"blocks\": [{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": message}}],\n        },\n        timeout=30,\n    )\n    if response.status_code != 200:\n        raise RuntimeError(\n            f\"Slack webhook returned {response.status_code}: {response.text[:200]}\"\n        )\n\n\ndef parse_dt(value):\n    return datetime.fromisoformat(value.replace(\"Z\", \"+00:00\"))\n\n\ndef item_status(item):\n    for field_value in (item.get(\"fieldValues\") or {}).get(\"nodes\", []):\n        if field_value.get(\"field\", {}).get(\"name\") == STATUS_FIELD:\n            return field_value.get(\"name\")\n    return None\n\n\ndef latest_check_in_time(comments):\n    times = [\n        parse_dt(comment[\"created_at\"])","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/script/github-guild-board.py#L393-L429","documentation":"The incoming-webhook POST returned a status other than 200 and the script raises with the code plus the first 200 characters of the body, which identify the cause: 400 invalid_payload, 404/410 deleted webhook or uninstalled app, 403 wrong workspace, 429 rate limited, 5xx Slack-side incident. There is no retry, so a single blip or an over-long message kills the notification.","triggerScenarios":"POST to the hooks.slack.com URL with a mrkdwn block exceeding Slack's 3000-char text limit returns 400 invalid_payload; the webhook was deleted or its app uninstalled returns 404/410; bursts faster than roughly one message per second return 429; Slack incidents return 5xx.","commonSituations":"Guild board summaries growing past block limits as the team grows; channel/webhook removed during a workspace reorg; CI retries spamming the webhook; incoming-webhook app uninstalled for a newer integration.","solutions":["Read the body snippet in the message: 'invalid_payload' means trim or split the blocks; 'no_team_found'/404 means recreate the webhook","Truncate each Slack text block to the 3000-char limit before sending","On 429 or 5xx, honor Retry-After and retry once or twice instead of failing the run","If the webhook is dead, create a new one and update the CI secret"],"exampleFix":"// before\nif response.status_code != 200:\n    raise RuntimeError(f\"Slack webhook returned {response.status_code}: {response.text[:200]}\")\n\n// after\nfor attempt in range(3):\n    if response.status_code == 200:\n        break\n    if response.status_code in (429, 500, 502, 503) and attempt < 2:\n        time.sleep(int(response.headers.get(\"Retry-After\", \"2\")))\n        response = requests.post(webhook, json=payload, timeout=30)\n        continue\n    raise RuntimeError(f\"Slack webhook returned {response.status_code}: {response.text[:200]}\")","handlingStrategy":"retry","validationCode":"def slack_blocks_within_limits(blocks: list) -> bool:\n    return all(\n        len(b.get(\"text\", {}).get(\"text\", \"\")) <= 3000\n        for b in blocks\n        if b.get(\"type\") == \"section\"\n    )","typeGuard":"def slack_post_succeeded(response) -> bool:\n    return response.status_code == 200","tryCatchPattern":"try:\n    send_slack(summary)\nexcept RuntimeError as exc:\n    status = exc.split(' ')[3] if ' ' in exc else ''\n    if ' 429' in str(exc) or ' 5' in str(exc):\n        time.sleep(5)\n        send_slack(summary)\n    else:\n        raise","preventionTips":["Truncate Slack text blocks to 3000 chars before posting","Honor Retry-After on 429 responses","Recreate webhooks promptly when apps/channels change and update the secret","Keep notifications idempotent so retries do not double-post"],"tags":["slack","webhook","rate-limit","network","python"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}