LINE error 400: Invalid reply token
Last verified against LINE Developers - Messaging API reference (error responses)
Invalid reply tokenWhat error 400 means
The reply endpoint (POST /v2/bot/message/reply) rejected the value you passed in replyToken. The reference gives exactly two reasons: you "sent a reply message using an expired reply token" or you "sent a reply message using a used reply token." Nothing is wrong with your channel access token, your message objects, or the user - if any of those were the problem you would see a different message, such as The request body has X error(s) or a 401. The token itself is spent or stale.
The contract behind this error is strict and worth quoting: "Reply tokens can only be used once" and "must be used within one minute after receiving the webhook. Use beyond one minute isn't guaranteed to work." One webhook event yields one reply token, that token buys you a single reply call (which may carry up to five message objects), and the meter starts the moment the webhook arrives. LINE adds that the time limit "is subject to change without notice" and that actual usable duration "may vary due to network delays and other factors" - so the docs explicitly tell you not to build logic that depends on the one-minute figure. Reply as soon as possible, full stop.
Redelivered webhooks are a special case that trips people up. A redelivered event carries the same reply token as the original, and it can be used within one minute of receiving the redelivery - but not if the original token was already used, and not if 20 minutes have passed since the event occurred. So a bot that replied to the original delivery and then blindly replies again to the redelivery will collect this error every time.
The economics matter too: replies are the free half of LINE's sending model. A reply that dies on this error and gets converted to a push message succeeds, but the push counts against your monthly plan quota (see monthly quota). Bots that habitually miss the reply window quietly become more expensive to run.
What it looks like
// If you specify an invalid reply token such as expired or used (400 Bad Request)
{
"message": "Invalid reply token"
}Why it happens
- Your handler replied twice to the same event - for example one reply per message object instead of batching up to five message objects into a single reply call.
- Processing (LLM call, database write, external API) took longer than the roughly one-minute token lifetime, so the token expired before the reply request went out.
- A redelivered webhook was answered even though the original delivery had already been replied to, or more than 20 minutes had passed since the event occurred.
- The token was persisted to a queue or database and consumed later, past its validity window.
- The replyToken string was truncated, re-encoded, or mixed up with another event's token in your pipeline.
How to fix LINE error 400
- 1Log the exact replyToken and the webhook receive timestamp next to every reply call, and measure the delta - anything approaching 60 seconds is inside the failure zone.
- 2Reply exactly once per event: batch up to 5 message objects into the messages array of a single reply request instead of making multiple calls.
- 3Return 200 to the webhook immediately and do slow work asynchronously, but issue the reply itself as early as possible - LINE's own guidance is to use reply tokens as soon as possible.
- 4For work you can't finish in time, send the reply first (even a short acknowledgment) or fall back to a push message to the event's source user ID once processing completes.
- 5For long processing, call the loading-animation endpoint to show progress, but note it doesn't extend the token's life - the reply must still go out within the window.
- 6On redelivered events (deliveryContext.isRedelivery = true), check whether you already handled the webhookEventId before attempting a reply.
How to stop it recurring
Treat the reply token as radioactive: consume it once, immediately, in the same process that received the webhook, and never store it beyond the request lifecycle. Deduplicate by webhookEventId so redeliveries can't trigger second replies. Design any flow that can exceed a minute as reply-then-push from day one, and monitor the ratio of replies falling back to push, since each fallback consumes paid monthly quota.
Official reference: LINE Developers - Messaging API reference (error responses). See all LINE error codes or the LINE limits and quotas.
Related codes
- 400: The request body has X error(s)The request body has X error(s) <detail varies>
- 429: You have reached your monthly limit.You have reached your monthly limit.
- 400: Failed to send messagesFailed to send messages
- 401: Authentication failedAuthentication failed due to the following reason: XXX <detail varies>
Error 400 - quick answers
What does LINE error 400 mean?
The reply endpoint ( POST /v2/bot/message/reply ) rejected the value you passed in replyToken .
How do I fix LINE error 400?
1. Log the exact replyToken and the webhook receive timestamp next to every reply call, and measure the delta - anything approaching 60 seconds is inside the failure zone. 2. Reply exactly once per event: batch up to 5 message objects into the messages array of a single reply request instead of making multiple calls. 3. Return 200 to the webhook immediately and do slow work asynchronously, but issue the reply itself as early as possible - LINE's own guidance is to use reply…
Should I retry after error 400?
No. Retrying the same request produces the same error; the condition has to be fixed first. Treat it as a permanent failure for that message and surface it, rather than looping.
Stop debugging LINE by hand
Connect the channel through Conferbot: tokens, webhooks and retries are handled, failures show as readable status.