Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for Slack By James Joyner IV · · 8 min read Last reviewed Jul 2026

Slack Error Guide: 'invalid_payload' — Fix Webhook Bodies

Quick answer

Fix the Slack incoming webhook invalid_payload error: send valid JSON as application/json, escape special characters, and keep Block Kit blocks well-formed.

  • #slack
  • #api
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this Slack error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

The invalid_payload error is returned by Slack incoming webhooks (the https://hooks.slack.com/services/... URLs) when the body you POST is not something Slack can parse into a message. Unlike Web API methods that return a JSON {ok:false,...}, an incoming webhook responds with a plain-text body and an HTTP 400. The cause is almost always malformed JSON: a trailing comma, an unescaped quote or newline inside text, a wrong Content-Type, sending form data instead of a JSON body, or blocks that don’t match Block Kit’s schema.

The webhook responds with HTTP 400 and this text body:

HTTP/2 400
content-type: text/plain

invalid_payload

It occurs whenever the POST body to an incoming webhook is not valid, well-formed JSON matching Slack’s message shape.

Symptoms

  • curl to a hooks.slack.com URL returns HTTP 400 with the literal text invalid_payload.
  • Messages with special characters (quotes, backslashes, newlines) fail while plain ones work.
  • Sending data as a form field or with the wrong Content-Type.
  • Dynamically built JSON breaks when a variable contains a quote or line break.
  • A blocks array with a malformed or unknown block.

Common Root Causes

1. Malformed JSON

A trailing comma, missing quote, or unbalanced brace makes the body unparseable.

2. Unescaped special characters in text

Raw double quotes, backslashes, or literal newlines inside a string field break the JSON.

3. Wrong Content-Type or form encoding

Posting payload={...} as a form field, or omitting Content-Type: application/json, so Slack doesn’t parse it as a JSON message.

4. Invalid Block Kit structure

A blocks entry missing a required field or using an unknown type.

5. Interpolating untrusted data directly into a JSON string

Building the body with string concatenation, so user/log content with quotes or newlines corrupts it.

Diagnostic Workflow

Step 1: Reproduce the malformed body

# Trailing comma -> invalid JSON
curl -s -o /dev/stderr -w "HTTP %{http_code}\n" -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d '{"text":"deploy done",}'
invalid_payload
HTTP 400

Step 2: Validate the JSON locally before sending

echo '{"text":"deploy done",}' | jq . 2>&1 | head -1
jq: error (at <stdin>:0): Objects must consist of key:value pairs

If jq can’t parse it, neither can Slack. Fix the JSON first.

Step 3: Build the body safely (let a tool do the escaping)

# jq escapes quotes/newlines in $MSG correctly
MSG='He said "deploy is done"
on prod'
BODY=$(jq -n --arg t "$MSG" '{text: $t}')
curl -s -w " HTTP %{http_code}\n" -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d "$BODY"
ok HTTP 200

A successful incoming webhook returns the literal text ok with HTTP 200.

Step 4: Validate blocks before posting

BODY=$(jq -n '{
  blocks: [
    {type:"header", text:{type:"plain_text", text:"Deploy complete"}},
    {type:"section", text:{type:"mrkdwn", text:"*service:* payments"}}
  ]
}')
curl -s -w " HTTP %{http_code}\n" -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" -d "$BODY"
ok HTTP 200

Well-formed blocks return ok; a bad block type or missing field returns invalid_payload.

Example Root Cause Analysis

A CI script notifies Slack with the last git commit message in the text. A commit whose message contains a double quote breaks the notification:

COMMIT='fix: handle "null" response from upstream'
curl -s -w " HTTP %{http_code}\n" -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d "{\"text\":\"Deployed: $COMMIT\"}"
invalid_payload HTTP 400

The commit message’s embedded quotes terminate the JSON string early, producing invalid JSON. The fix is to build the body with jq (or the language’s JSON serializer) so special characters are escaped correctly instead of hand-concatenating strings:

BODY=$(jq -n --arg t "Deployed: $COMMIT" '{text: $t}')
curl -s -w " HTTP %{http_code}\n" -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" -d "$BODY"
ok HTTP 200

Letting a JSON serializer handle escaping makes the notification robust to any commit message.

Prevention Best Practices

  • Never hand-concatenate JSON; build the body with jq or your language’s JSON serializer so quotes, backslashes, and newlines are escaped.
  • Always send Content-Type: application/json with a raw JSON body — not a payload= form field.
  • Validate the JSON (and Block Kit structure) locally before sending; treat a jq parse failure as a blocked send.
  • Test messages with adversarial content (quotes, emoji, multi-line, backslashes) so escaping is exercised.
  • Keep payloads within Slack’s size limits and use Block Kit Builder to validate complex block layouts.
  • For ad-hoc triage, the free incident assistant can pinpoint the character that broke a webhook body. See more in Slack guides.

Quick Command Reference

# Validate JSON before sending
echo "$BODY" | jq . >/dev/null && echo "valid" || echo "INVALID JSON"

# Build a safe text payload with jq
BODY=$(jq -n --arg t "$MSG" '{text: $t}')

# Post to an incoming webhook (expect: ok / HTTP 200)
curl -s -w " HTTP %{http_code}\n" -X POST "$SLACK_WEBHOOK_URL" \
  -H "Content-Type: application/json" -d "$BODY"

Conclusion

invalid_payload from an incoming webhook means the POST body isn’t valid JSON in Slack’s message shape. The usual root causes:

  1. Malformed JSON (trailing comma, unbalanced braces).
  2. Unescaped quotes, backslashes, or newlines in text.
  3. Wrong Content-Type or form-encoded body.
  4. Invalid Block Kit structure.
  5. Concatenating untrusted data straight into the JSON string.

Build the body with a real JSON serializer, send it as application/json, validate it locally first, and a healthy webhook will return ok.

Free download · 368-page PDF

Fixed it? Get 500 Slack & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.