Your LLM Bot's Reply Is Too Long for Discord

·5 min read·Updated
discordbotsllmai-agentstroubleshooting

Put a language model behind a Discord bot and you meet a limit the model knows nothing about: message content caps at 2,000 characters. A thorough answer sails past that, and the usual reactions all have problems — truncating loses the end of the answer, splitting on a fixed character count cuts through code fences and leaves broken formatting, and posting a wall of consecutive messages is unpleasant to read. The fix has two halves: constrain the output before you generate it, and split on real boundaries when it's still too long. Embeds buy you more room, and a file attachment removes the problem entirely for genuinely long output.

The limits you're working with

Message content is capped at 2,000 characters. Embeds are more generous, and Discord's reference is precise about them:

Field Limit
Embed title "256 characters"
Embed description "4096 characters"
Fields per embed "Up to 25 field objects"
Field name "256 characters"
Field value "1024 characters"
Footer text "2048 characters"

And the one people miss — there's a ceiling across the whole message: "the combined sum of characters in all title, description, field.name, field.value, footer.text, and author.name fields across all embeds attached to a message must not exceed 6000 characters" (Discord docs).

So an embed roughly doubles your room, and stacking embeds doesn't scale past 6,000.

Fix the cause first: cap the output

Splitting is a workaround. The better first move is to stop generating more than you can display.

  • Set max_tokens on the model call, sized to your target. It bounds the worst case rather than discovering it afterwards, and it's a configuration value worth keeping in an environment variable so you can tune it without a deploy.
  • Ask for brevity in the system prompt. "Answer in under 1,500 characters" works well enough to matter, and combines with the hard cap rather than replacing it.
  • Remember it's also cheaper. Output tokens are billed, so a bot that rambles costs more per answer — the same budget you're already rate-limiting.

Truncating mid-sentence after generation is the worst of both: you paid for the tokens and the user gets a cut-off answer.

Split on boundaries, not counts

When output still overflows, split deliberately. A naive chunk[i:i+2000] will eventually cut through a code fence and leave the rest of the conversation rendering as code.

The rules that matter:

  1. Prefer paragraph breaks, then line breaks, then sentence ends. Only fall back to a hard character split if a single line exceeds the limit.
  2. Track fenced code blocks. If a split lands inside one, close the fence at the end of the first chunk and reopen it (with the same language) at the start of the next.
  3. Leave headroom. Budget a hundred characters or so for the fences and any continuation marker you add, so a chunk that's exactly at the limit doesn't fail after you decorate it.
  4. Send in order and wait. Fire-and-forget sends can arrive out of order, which turns a split answer into a jumbled one.

Most bot libraries have a helper for this. Use it rather than writing the fifth version of this function.

Or attach a file

For output that's genuinely long — a generated document, a long analysis, a diff — a text or Markdown attachment is better than any splitting strategy. One message, no ordering issues, no formatting damage, and the user can save it.

A good pattern is a short summary in the message plus the full text attached. That reads well in a channel and stays useful in search.

The deadline and the edit trap

Two Discord behaviours interact badly with model latency, and both have appeared here before.

You have about three seconds to acknowledge an interaction, which no model call reliably fits inside. Defer immediately, then edit the message once you have an answer — the full pattern.

Don't edit on every token. The obvious way to fake streaming is to edit the message as tokens arrive, and it's a very effective way to generate rate-limit responses. Every 429 counts toward the invalid-request limit, so an enthusiastic edit loop can escalate from "throttled" to "temporarily restricted".

If you want a streaming feel, edit on a timer — every second or two, or every few hundred characters — not on every chunk. The perceived difference is small and the request count is an order of magnitude lower.

Watch what you log

A related habit worth keeping: don't log full model responses by default. They're long, your log stream is capped and rotates, and a few verbose answers will push out the errors you actually needed. Log lengths, token counts, and identifiers; keep bodies behind a debug flag.

FAQ

What's the Discord message character limit?

Message content is capped at 2,000 characters. Embed descriptions allow up to 4,096, with a 6,000-character combined ceiling across all embeds in a message.

How should I handle a model reply that's too long?

Cap the output with max_tokens first. If it still overflows, split on paragraph or line boundaries, or attach the full text as a file.

Why is my split message showing everything as code?

The split landed inside a fenced code block. Close the fence at the end of a chunk and reopen it at the start of the next.

Can I just use embeds for long answers?

They roughly double your room, but the combined limit across embeds is 6,000 characters, so they don't scale indefinitely.

Should I edit the message as tokens stream in?

Not on every token. Edit on a timer instead — frequent edits generate rate-limit responses, which count toward a stricter limit.

Does the three-second deadline apply to the whole answer?

No, only to acknowledging the interaction. Defer straight away, then edit with the result when the model finishes.

Wrapping up

This is a small problem that produces a disproportionately bad experience — cut-off answers, mangled code blocks, a channel full of fragments. Most of it disappears by deciding how long a reply should be before generating it, which also costs less. Keep a boundary-aware splitter for the rest, reach for an attachment when the output is genuinely a document, and resist the urge to edit the message on every token.