Перейти к содержимому
Все статьи
· Обновлено 23 апреля 2026 г.

Лимиты Discord Embed — шпаргалка (символы, поля, общий payload)

Все лимиты Discord embed в одном месте: title, description, fields, footer, общий размер. С кодом валидации на Python и JavaScript для отлова переполнения до отправки.

лимиты embedвалидациясимволыполяpayloadwebhookdiscord api
Лимиты Discord Embed — шпаргалка (символы, поля, общий payload)

Discord отклоняет переразмеренные embed’ы общим 400 Bad Request. Сообщение об ошибке редко информативное — просто «что-то слишком длинное», без указания поля. Этот гайд — полная шпаргалка всех embed-лимитов Discord на 2026 + готовые валидаторы на Python и JavaScript, которые скажут, какой именно лимит вы пробили, до удара в Discord API.

Цифры (2026)

На один embed

ПолеМаксИдёт в общий счёт?
title256 симвда
description4096 симвда
fields25 элементов
field.name256 симвда
field.value1024 симвда
footer.text2048 симвда
author.name256 симвда
url, image.url, thumbnail.url, author.url, footer.icon_url, author.icon_url2048 симвнет
color24-битное число (0–16777215)
timestampISO-8601

На сообщение

ПолеМакс
content2000 симв (4000 с Nitro)
embeds10 на сообщение
Общий текст embed’ов (сумма title + description + field.name + field.value + footer.text + author.name по всем embed’ам)6000 симв
attachments10 файлов
Размер файла25 МБ free / 50–500 МБ от tier’а

Webhook-специфичное

ПолеМакс
username80 симв (не «Clyde» и не «Discord»)
avatar_url2048 симв
thread_name100 симв (при создании треда форума)

Ловушка: общий лимит 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 Webhook