Лимиты Discord Embed — шпаргалка (символы, поля, общий payload)
Все лимиты Discord embed в одном месте: title, description, fields, footer, общий размер. С кодом валидации на Python и JavaScript для отлова переполнения до отправки.
Discord отклоняет переразмеренные embed’ы общим 400 Bad Request. Сообщение об ошибке редко информативное — просто «что-то слишком длинное», без указания поля. Этот гайд — полная шпаргалка всех embed-лимитов Discord на 2026 + готовые валидаторы на Python и JavaScript, которые скажут, какой именно лимит вы пробили, до удара в Discord API.
Цифры (2026)
На один embed
| Поле | Макс | Идёт в общий счёт? |
|---|---|---|
title | 256 симв | да |
description | 4096 симв | да |
fields | 25 элементов | — |
field.name | 256 симв | да |
field.value | 1024 симв | да |
footer.text | 2048 симв | да |
author.name | 256 симв | да |
url, image.url, thumbnail.url, author.url, footer.icon_url, author.icon_url | 2048 симв | нет |
color | 24-битное число (0–16777215) | — |
timestamp | ISO-8601 | — |
На сообщение
| Поле | Макс |
|---|---|
content | 2000 симв (4000 с Nitro) |
embeds | 10 на сообщение |
Общий текст embed’ов (сумма title + description + field.name + field.value + footer.text + author.name по всем embed’ам) | 6000 симв |
attachments | 10 файлов |
| Размер файла | 25 МБ free / 50–500 МБ от tier’а |
Webhook-специфичное
| Поле | Макс |
|---|---|
username | 80 симв (не «Clyde» и не «Discord») |
avatar_url | 2048 симв |
thread_name | 100 симв (при создании треда форума) |
Ловушка: общий лимит 6000
Технически можно держать 10 embed’ов × 4096 description = 40 960 символов… но Discord отклоняет всё, что суммарно по тексту всех embed’ов больше 6000. Влетит 400, даже если ни одно поле отдельно не превысило свой лимит.
На этом ловятся те, кто строит дашборды из множества embed’ов — на масштабе общий лимит пробивается раньше любого индивидуального.
Валидатор на Python
from typing import Any
class EmbedLimitError(ValueError):
pass
LIMITS = {
"title": 256,
"description": 4096,
"field.name": 256,
"field.value": 1024,
"footer.text": 2048,
"author.name": 256,
"username": 80,
"content": 2000,
}
TOTAL_EMBED_CHARS = 6000
MAX_FIELDS = 25
MAX_EMBEDS = 10
def _len(s: Any) -> int:
return len(s) if isinstance(s, str) else 0
def validate_embed(e: dict, idx: int = 0) -> int:
"""Валидирует один embed, возвращает суммарный счёт символов."""
total = 0
if _len(e.get("title")) > LIMITS["title"]:
raise EmbedLimitError(f"embeds[{idx}].title > {LIMITS['title']}")
total += _len(e.get("title"))
if _len(e.get("description")) > LIMITS["description"]:
raise EmbedLimitError(f"embeds[{idx}].description > {LIMITS['description']}")
total += _len(e.get("description"))
fields = e.get("fields", [])
if len(fields) > MAX_FIELDS:
raise EmbedLimitError(f"embeds[{idx}].fields > {MAX_FIELDS} элементов")
for fi, f in enumerate(fields):
if _len(f.get("name")) > LIMITS["field.name"]:
raise EmbedLimitError(f"embeds[{idx}].fields[{fi}].name > {LIMITS['field.name']}")
if _len(f.get("value")) > LIMITS["field.value"]:
raise EmbedLimitError(f"embeds[{idx}].fields[{fi}].value > {LIMITS['field.value']}")
total += _len(f.get("name")) + _len(f.get("value"))
footer = e.get("footer", {})
if _len(footer.get("text")) > LIMITS["footer.text"]:
raise EmbedLimitError(f"embeds[{idx}].footer.text > {LIMITS['footer.text']}")
total += _len(footer.get("text"))
author = e.get("author", {})
if _len(author.get("name")) > LIMITS["author.name"]:
raise EmbedLimitError(f"embeds[{idx}].author.name > {LIMITS['author.name']}")
total += _len(author.get("name"))
return total
def validate_payload(payload: dict) -> None:
"""Кидает EmbedLimitError, если хоть один лимит пробит."""
if _len(payload.get("content")) > LIMITS["content"]:
raise EmbedLimitError(f"content > {LIMITS['content']}")
if _len(payload.get("username")) > LIMITS["username"]:
raise EmbedLimitError(f"username > {LIMITS['username']}")
embeds = payload.get("embeds", [])
if len(embeds) > MAX_EMBEDS:
raise EmbedLimitError(f"embeds > {MAX_EMBEDS}")
grand_total = sum(validate_embed(e, i) for i, e in enumerate(embeds))
if grand_total > TOTAL_EMBED_CHARS:
raise EmbedLimitError(f"общий счёт {grand_total} > {TOTAL_EMBED_CHARS}")
Используйте перед каждым requests.post:
import requests
payload = {"embeds": [{"title": "x" * 300}]} # выше 256
try:
validate_payload(payload)
except EmbedLimitError as e:
print(f"Не отправляем: {e}")
else:
requests.post(WEBHOOK_URL, json=payload)
Валидатор на JavaScript / TypeScript
interface Embed {
title?: string;
description?: string;
fields?: Array<{ name: string; value: string; inline?: boolean }>;
footer?: { text?: string };
author?: { name?: string };
}
interface Payload {
content?: string;
username?: string;
embeds?: Embed[];
}
const LIMITS = {
title: 256,
description: 4096,
fieldName: 256,
fieldValue: 1024,
footerText: 2048,
authorName: 256,
username: 80,
content: 2000,
};
const TOTAL_CHARS = 6000;
const MAX_FIELDS = 25;
const MAX_EMBEDS = 10;
const len = (s?: string) => (typeof s === 'string' ? s.length : 0);
function validateEmbed(e: Embed, idx = 0): number {
let total = 0;
if (len(e.title) > LIMITS.title) throw new Error(`embeds[${idx}].title > ${LIMITS.title}`);
total += len(e.title);
if (len(e.description) > LIMITS.description)
throw new Error(`embeds[${idx}].description > ${LIMITS.description}`);
total += len(e.description);
const fields = e.fields ?? [];
if (fields.length > MAX_FIELDS)
throw new Error(`embeds[${idx}].fields > ${MAX_FIELDS}`);
fields.forEach((f, fi) => {
if (len(f.name) > LIMITS.fieldName)
throw new Error(`embeds[${idx}].fields[${fi}].name > ${LIMITS.fieldName}`);
if (len(f.value) > LIMITS.fieldValue)
throw new Error(`embeds[${idx}].fields[${fi}].value > ${LIMITS.fieldValue}`);
total += len(f.name) + len(f.value);
});
if (len(e.footer?.text) > LIMITS.footerText)
throw new Error(`embeds[${idx}].footer.text > ${LIMITS.footerText}`);
total += len(e.footer?.text);
if (len(e.author?.name) > LIMITS.authorName)
throw new Error(`embeds[${idx}].author.name > ${LIMITS.authorName}`);
total += len(e.author?.name);
return total;
}
export function validatePayload(p: Payload): void {
if (len(p.content) > LIMITS.content) throw new Error(`content > ${LIMITS.content}`);
if (len(p.username) > LIMITS.username) throw new Error(`username > ${LIMITS.username}`);
const embeds = p.embeds ?? [];
if (embeds.length > MAX_EMBEDS) throw new Error(`embeds > ${MAX_EMBEDS}`);
const grand = embeds.reduce((sum, e, i) => sum + validateEmbed(e, i), 0);
if (grand > TOTAL_CHARS) throw new Error(`общий счёт ${grand} > ${TOTAL_CHARS}`);
}
Хелпер обрезки
Если ввод может переполнить — обрезайте с многоточием:
def truncate(s: str, n: int) -> str:
return s if len(s) <= n else s[:n - 1] + "…"
embed = {
"title": truncate(user_title, 256),
"description": truncate(user_body, 4096),
"fields": [
{"name": truncate(k, 256), "value": truncate(v, 1024), "inline": True}
for k, v in metadata.items()
][:25], # ограничить и количество полей
}
Как Discord считает символы
- По code point, не по байтам. Кириллица
Яи эмодзи🚀обе считаются как 1 (эмодзи бывают 1–4 code point, но Discord меряет по отрисовке) - Markdown (
**bold**) считается — звёздочки съедают 4 символа - Кастомные эмодзи (
<:name:123>) считаются как длина строки (~17 симв) - Упоминания (
<@123>) — тоже по длине строки
Если ваш ввод ровно 4096 символов и содержит markdown — после рендера будете за лимитом. Закладывайте оверхед markdown в бюджет обрезки.
Особенности color
color — одно 24-битное число, не RGB-массив и не hex-строка:
// hex → число
const fromHex = (hex) => parseInt(hex.replace('#', ''), 16);
const embed = { color: fromHex('#5865f2') }; // 5793266
color: 0 делает embed «прозрачным» (нет левой полосы). Если нужна чёрная — color: 1.
Inline-поля
inline: true позволяет до 3 полей делить ряд. Discord переносит автоматически:
"fields": [
{ "name": "CPU", "value": "12%", "inline": true },
{ "name": "Mem", "value": "440 MB", "inline": true },
{ "name": "Disk", "value": "67%", "inline": true },
{ "name": "Region", "value": "us-east", "inline": true }
]
CPU/Mem/Disk в одном ряду, Region переносится. Длинные inline-значения тоже ломают сетку — держите под ~30 символов для аккуратной таблицы.
Быстрая валидация в браузере
Прототипируете — наш конструктор Discord Webhook показывает счётчик символов для каждого поля и предупреждает при пробое до отправки. В пару — гайд Embed Builder и справочник по цветам.
Источники
- Discord docs: Embed Object
- Discord docs: Embed Limits
Попробуйте в нашем инструменте
Открыть конструктор Discord Webhook