Slack Error Guide: 'cant_update_message' — Fix Edit Failures
Fix the Slack cant_update_message error: a bot can only edit its own messages, so match your token identity to the message author before chat.update.
- #slack
- #api
- #troubleshooting
- #errors
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 cant_update_message error is returned by chat.update when the message exists but the authenticated token is not allowed to edit it. The core rule in Slack is that a message can only be edited by the identity that authored it: a bot can update messages it posted, and a user token can update that user’s own messages. Trying to edit a message written by a person, by a different bot, by an incoming webhook, or one posted as another identity (as_user) yields cant_update_message. It differs from message_not_found — here the message is located, but ownership fails.
Slack returns HTTP 200 with ok:false:
{
"ok": false,
"error": "cant_update_message"
}
It occurs when the calling token’s identity does not match the message’s author.
Symptoms
chat.updatefinds the message (nomessage_not_found) but rejects the edit.- A bot tries to edit a message posted by a human or by an incoming webhook.
- Editing works for messages the bot posted but fails for older ones posted under a different token/app.
- Attempting to update a message posted with
as_user:trueunder a user that no longer authorizes the app. - Trying to update an ephemeral message.
Common Root Causes
1. The message was authored by a different identity
The most common cause: the token calling chat.update is not the author. Bot tokens can only edit their own bot messages.
2. The message came from an incoming webhook
Incoming webhook messages are not owned by your bot user and cannot be edited via chat.update.
3. Human-authored messages
A bot cannot edit a person’s message. Only that user’s own token could, and only within the app’s permissions.
4. Posted as another user (as_user)
If a message was posted with as_user semantics under a user whose authorization changed, the token may no longer be able to edit it.
5. Ephemeral messages
chat.postEphemeral output is transient and cannot be updated.
Diagnostic Workflow
Step 1: Confirm the message exists (rule out message_not_found)
curl -s -G "https://slack.com/api/conversations.history" \
--data-urlencode "channel=C0123456789" \
--data-urlencode "latest=1720526400.001900" \
--data-urlencode "inclusive=true" --data-urlencode "limit=1" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
| jq '.messages[0] | {ts, user, bot_id, app_id, subtype}'
{
"ts": "1720526400.001900",
"user": "U04HUMAN01",
"bot_id": null,
"app_id": null,
"subtype": null
}
A user id with bot_id:null means a human authored it — a bot cannot edit it.
Step 2: Identify your token’s own identity
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" | jq '{user_id, bot_id}'
{
"user_id": "U0BOTBOT01",
"bot_id": "B08BOT0001"
}
Compare this bot_id to the message’s bot_id. They must match for chat.update to succeed.
Step 3: Reproduce the ownership failure
curl -s -X POST https://slack.com/api/chat.update \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","ts":"1720526400.001900","text":"edited"}' | jq .error
"cant_update_message"
Step 4: Verify against a message the bot DID author
# Post as the bot, then update it — this should succeed
TS=$(curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"bot msg"}' | jq -r '.ts')
curl -s -X POST https://slack.com/api/chat.update \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"ts\":\"$TS\",\"text\":\"bot msg (edited)\"}" | jq .ok
true
Editing the bot’s own message works, confirming the failure was ownership, not the payload.
Example Root Cause Analysis
A status bot is supposed to keep a single “current deploy” message updated. It was recently migrated from an incoming webhook to a bot token, but the message it tries to edit was posted by the old webhook:
curl -s -G "https://slack.com/api/conversations.history" \
--data-urlencode "channel=C0123456789" --data-urlencode "latest=1720526400.001900" \
--data-urlencode "inclusive=true" --data-urlencode "limit=1" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" | jq '.messages[0] | {bot_id, app_id, subtype}'
{
"bot_id": "B01WEBHOOK9",
"app_id": "A01WEBHOOK9",
"subtype": "bot_message"
}
The message’s bot_id (B01WEBHOOK9) belongs to the retired webhook integration, not the new bot (B08BOT0001), so the edit is refused. The fix is to have the new bot POST its own status message and update that one going forward:
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"deploy: in progress"}' | jq -r '.ts'
1720526799.004100
From then on the bot updates the message it authored, and cant_update_message disappears.
Prevention Best Practices
- Only update messages your bot authored; store the
tsof messages the bot itself posts and edit those. - Compare
auth.test.bot_idto the message’sbot_idbefore attemptingchat.updateif ownership is ever uncertain. - Migrate off incoming webhooks to a bot token if you need editable messages — webhook posts are not editable.
- Never attempt to edit human-authored messages from a bot; design the workflow to post a new bot message instead.
- Track
chat.postEphemeraloutput separately; it cannot be updated or deleted. - For ad-hoc triage, the free incident assistant can compare authoring bot_id to your token identity. See more in Slack guides.
Quick Command Reference
# Who is this token?
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" | jq '{user_id, bot_id}'
# Who authored the message?
curl -s -G "https://slack.com/api/conversations.history" \
--data-urlencode "channel=C0123456789" --data-urlencode "latest=TS" \
--data-urlencode "inclusive=true" --data-urlencode "limit=1" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" | jq '.messages[0] | {user, bot_id, app_id}'
# Update a message the bot authored
curl -s -X POST https://slack.com/api/chat.update \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","ts":"TS","text":"edited"}' | jq .ok
Conclusion
cant_update_message means the message exists but the calling token is not its author. The usual root causes:
- The message was posted by a different bot or app.
- It came from an incoming webhook (not editable).
- It was authored by a human.
- It was posted
as_userunder an identity that changed. - It is an ephemeral message.
Only edit messages your bot posted: match your auth.test identity to the message’s bot_id, and if you inherited an unowned message, post a fresh one and update that instead.
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?
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.