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 · · 9 min read Last reviewed Jul 2026

Slack Error Guide: 'message_not_found' — Fix Bad Timestamps

Quick answer

Fix the Slack message_not_found error: pass the exact ts as a string with its matching channel to chat.update and chat.delete, and handle deleted messages.

  • #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 message_not_found error means Slack could not locate a message with the ts (timestamp) you supplied in the channel you supplied. It appears on chat.update, chat.delete, reactions.add, reactions.remove, pins.add, and chat.getPermalink. In Slack, a message is uniquely identified by the pair (channel, ts) — the ts alone is not global. The most common cause is a mismatched or reformatted ts: truncating it, rounding it, or pairing it with the wrong channel id. Editing a live status message or deleting a completed deploy notice is where this usually bites.

Slack returns HTTP 200 with ok:false:

{
    "ok": false,
    "error": "message_not_found"
}

It occurs whenever (channel, ts) does not point at an existing message the token can act on.

Symptoms

  • chat.update / chat.delete fails with message_not_found right after a successful chat.postMessage.
  • Reactions fail on a message that clearly exists in the UI.
  • A ts copied from a URL or logged as a float has lost precision.
  • Editing a threaded reply using the parent’s channel but a reply’s ts, or vice versa.
  • The message was already deleted by a user or another process.

Common Root Causes

1. Wrong or reformatted ts

The ts is a string like 1720526400.001900. Storing it as a float, rounding it, or dropping trailing zeros changes the value so it no longer matches.

2. Mismatched channel

You must pass the SAME channel id the message was posted to. Using a DM id, a different channel, or the user id instead of the channel breaks the pair.

3. The message was deleted

A user or another automation already removed the message; there is nothing to update.

4. Using thread_ts instead of the message ts (or vice versa)

Acting on a reply requires that reply’s own ts, not the parent thread_ts.

5. Ephemeral messages

Messages posted with chat.postEphemeral have no permanent ts you can update or delete.

Diagnostic Workflow

Step 1: Capture the ts exactly at post time

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 starting..."}' \
  | jq '{ok, channel, ts}'
{
  "ok": true,
  "channel": "C0123456789",
  "ts": "1720526400.001900"
}

Store ts as a STRING with full precision — never parse it into a number.

Step 2: Reproduce the failure with a mangled 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":"1720526400.0019","text":"deploy done"}' | jq .error
"message_not_found"

Dropping the final 00 changed the timestamp; the pair no longer matches.

Step 3: Verify the message exists with the exact pair

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, text}'
{
  "ts": "1720526400.001900",
  "text": "deploy starting..."
}

If this returns nothing, the message was deleted or the channel/ts is wrong.

Step 4: Update with the exact, unmodified values

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":"deploy done ✅"}' \
  | jq '{ok, ts}'
{
  "ok": true,
  "ts": "1720526400.001900"
}

Example Root Cause Analysis

A deploy bot posts a “starting” message, saves the ts to a job record, then updates it to “finished”. The update fails intermittently:

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.0019,"text":"finished"}' | jq .error
"message_not_found"

The job record stores ts in a JSON number field, so 1720526400.001900 is serialized back as 1720526400.0019 — the trailing zeros and full precision are lost. The fix is to persist ts as a string everywhere:

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":"finished"}' | jq .ok
true

Keeping the timestamp a string preserves the exact value and the update succeeds every time.

Prevention Best Practices

  • Always store and pass ts as a string with full precision; never round-trip it through a float/number type.
  • Persist the (channel, ts) pair together and pass both to every follow-up call.
  • For threaded replies, keep each reply’s own ts distinct from the parent thread_ts.
  • Before updating, tolerate a missing message: catch message_not_found and decide whether to repost or no-op.
  • Remember chat.postEphemeral messages cannot be updated or deleted — track them differently.
  • For ad-hoc triage, the free incident assistant can spot a truncated timestamp in a failing update. See more in Slack guides.

Quick Command Reference

# Post and capture the exact ts (string)
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":"hi"}' | jq -r '.ts'

# Verify (channel, ts) points at a real message
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'

# Update using the exact string 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":"1720526400.001900","text":"done"}' | jq .ok

Conclusion

message_not_found means the (channel, ts) pair does not resolve to a message the token can act on. The usual root causes:

  1. A reformatted or precision-lost ts (stored as a number).
  2. Pairing the ts with the wrong channel id.
  3. The message was already deleted.
  4. Confusing a reply’s ts with the parent thread_ts.
  5. Trying to update/delete an ephemeral message.

Keep ts a full-precision string, always pair it with its original channel, and verify the message exists before acting on it.

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.