Обработка ошибок и автоматические повторы
Socialift SDK сводит ошибки всех платформ в одну иерархию: AuthError — невалидный токен, PermissionError — не хватает разрешений, RateLimitError — лимит, NotFoundError — объекта нет, TransportError — сетевой сбой. Ошибки лимитов, ответы HTTP 429 и 5xx и обрывы сети автоматически повторяются по RetryPolicy: по умолчанию 3 попытки, экспоненциальная задержка от 0,5 секунды и jitter.
Обновлено:
Какие ошибки перехватывать?
Сначала конкретные классы, общий ApiError — в конце. AuthError — отправьте пользователя переподключиться; PermissionError — исправьте scopes или пройдите App Review, повтор не поможет; RateLimitError — повторите позже с retry_after или своей задержкой; TransportError — проблема сети, обычно временная. Ошибки лицензии (LicenseError) — отдельная ветка, в ApiError не входят.
Иерархия ошибок и атрибуты
| Класс | Родитель | Атрибуты | Значение |
|---|---|---|---|
SocialiftError | Exception | нет | Все ошибки SDK, включая лицензионные |
ConfigurationError | SocialiftError | нет | Не хватает настройки или она неверна (например, пустой app_id); возникает до отправки запроса |
ApiError | SocialiftError | message, provider, status, code, subcode, payload, url | API платформы вернул ошибку |
AuthError | ApiError | как у ApiError | Токен невалиден, истёк или отозван |
PermissionError | ApiError | как у ApiError | Не хватает разрешения (scope), App Review или прав в чате |
RateLimitError | ApiError | ApiError + retry_after (секунды или None) | Лимит запросов — нужно подождать и повторить |
NotFoundError | ApiError | как у ApiError | Объекта нет или он не виден владельцу токена |
TransportError | SocialiftError | url | Обрыв соединения, DNS или таймаут — HTTP-статуса нет |
LicenseError | SocialiftError | нет | Ошибки лицензии — см. страницу «Аутентификация» |
естьнетТаблицу можно прокрутить вбок
Примечания и ограничения
socialift.PermissionError совпадает по имени со встроенным PermissionError Python — импортируйте с псевдонимом: from socialift import PermissionError as ScopeError. Формат str(exc): [provider] сообщение (HTTP status, code=...).
В какой класс попадает ошибка платформы?
SDK классифицирует ошибки по этим правилам; всё, что не подошло, остаётся обычным ApiError.
| Класс | Meta (Facebook, Instagram, Ads) | TikTok | Telegram Bot API | |
|---|---|---|---|---|
RateLimitError | code 4, 17, 32, 613 или HTTP 429 | HTTP 429 | rate_limit_exceeded, spam_risk_too_many_posts, spam_risk или HTTP 429 | HTTP 429 или parameters.retry_after в ответе |
AuthError | code 190, 102 или HTTP 401 | HTTP 401 | access_token_invalid, access_token_expired, invalid_access_token, token_not_found или HTTP 401 | HTTP 401 или «unauthorized» в описании |
PermissionError | code 10, 200–299 или HTTP 403 | HTTP 403 | scope_not_authorized, scope_permission_missed, unaudited_client_can_only_post_to_private_accounts, url_ownership_unverified, spam_risk_user_banned_from_posting или HTTP 403 | HTTP 403 или «forbidden» в описании (например, пользователь заблокировал бота) |
NotFoundError | code 803 или HTTP 404 | HTTP 404 | publish_id_not_found, video_not_found или HTTP 404 | HTTP 404 или «not found» в описании |
Примечания и ограничения
Порядок проверки: лимит → auth → разрешения → не найдено. У Meta exc.code — это error.code, exc.subcode — error_subcode, сообщение берётся из error_user_msg (если есть) или message. У LinkedIn exc.code — serviceErrorCode. У TikTok строковый код важнее HTTP-статуса, exc.code остаётся пустым, исходный код — в exc.payload, а log_id добавляется в текст сообщения. У Telegram exc.code — error_code, а токен бота в exc.url маскируется.
Как переводятся ошибки аккаунта Telegram (MTProto)?
TelegramAccount переводит исключения Telethon в ту же иерархию, поэтому один блок except работает и для бота, и для аккаунта, и для других платформ.
RateLimitErrorFloodWaitErrorи другие ошибкиFlood…;code=420,retry_after— секунды, названные Telegram. SDK сам не ждёт: решение за вами, чтобы 20-минутное ожидание не заморозило приложение.AuthErrorAuthKeyUnregisteredError,SessionRevokedError,SessionExpiredError,UserDeactivatedError,AuthKeyDuplicatedError,UnauthorizedError— сессия невалидна, аккаунт нужно переподключить (status=401).PermissionErrorChatAdminRequiredError,ChatWriteForbiddenError,UserBannedInChannelError,ChannelPrivateError,UserPrivacyRestrictedError,MessageDeleteForbiddenError,AdminsTooMuchError,UserNotParticipantError,ChatRestrictedError(status=403).NotFoundErrorUsernameNotOccupiedError,PeerIdInvalidError,MessageIdInvalidError,ChannelInvalidError,UserIdInvalidError,InviteHashInvalidErrorиValueError, который Telethon бросает, не найдя объект (status=404).TransportErrorConnectionError,OSError,TimeoutError— связь с Telegram прервалась.
Что означают коды ошибок Meta?
Ошибка Meta Graph API приходит в объекте error: message, type, code, error_subcode, error_user_title, error_user_msg, fbtrace_id. SDK сохраняет весь ответ в exc.payload — там же fbtrace_id, который нужен при обращении в поддержку Meta.
По документации Meta: 4 — лимит на уровне приложения, 17 — на уровне пользователя, 32 — на уровне страницы в Pages API, 613 — отдельный лимит endpoint; 190 — access token истёк или невалиден, 102 — сессия API; 10 — разрешение не выдано или отозвано, 200–299 — ошибки конкретных разрешений.
Стандартный заголовок Retry-After для лимитов Meta не документирует; для лимитов Business Use Case ориентировочное время ожидания приходит в поле estimated_time_to_regain_access заголовка X-Business-Use-Case-Usage (в минутах). Поэтому у RateLimitError от Meta retry_after обычно None — задержку задавайте сами.
Какие ошибки повторяются автоматически?
В клиентах Facebook, Instagram, Ads, LinkedIn, TikTok и Telegram SDK повторяет запрос в трёх случаях: RateLimitError; ApiError с HTTP 429, 500, 502, 503 или 504; TransportError (ошибки соединения aiohttp и таймауты). AuthError, PermissionError, NotFoundError и прочие 4xx поднимаются сразу. Когда попытки заканчиваются, поднимается последняя ошибка.
Задержка: если провайдер прислал заголовок Retry-After, SDK ждёт ровно столько — это значение не ограничивается backoff_max. Иначе работает формула RetryPolicy. Каждый повтор после HTTP-ошибки пишется в логгер socialift с уровнем WARNING.
Исключения: если TikTok вернул ошибку в теле ответа с HTTP 200, она поднимается без повторов. TelegramAccount (MTProto) RetryPolicy не использует: FloodWaitError сразу становится RateLimitError, а попытки подключения управляются параметром connection_retries.
Таймауты и ошибки соединения повторяются и для POST-запросов. Если запрос дошёл до платформы, а ответ потерялся, действие может выполниться дважды — для операций записи, где повтор опасен, используйте отдельный клиент с RetryPolicy(attempts=1).
Значения RetryPolicy по умолчанию
| Параметр | По умолчанию | Значение |
|---|---|---|
attempts | 3 | Общее число попыток, включая первую |
backoff_base | 0.5 | Основа первой задержки, секунды |
backoff_max | 30.0 | Верхняя граница задержки (до jitter), секунды |
jitter | True | Умножает задержку на случайный коэффициент 0,5–1,5 |
timeout (параметр клиента) | 30.0 | Общий таймаут одного HTTP-запроса, секунды |
Примечания и ограничения
Формула: min(backoff_base × 2^(n−1), backoff_max), затем jitter. С настройками по умолчанию после первой ошибки ожидание около 0,25–0,75 с, после второй — 0,5–1,5 с, третья ошибка поднимается.
Как передать свою RetryPolicy?
import os
from socialift import Facebook, RetryPolicy, Telegram
# Для фоновых задач: больше попыток, длиннее задержка и таймаут
patient = RetryPolicy(attempts=5, backoff_base=1.0, backoff_max=60.0)
fb = Facebook.from_env(retry=patient, timeout=60.0)
# Для операций записи, где повтор опасен: без повторов
once = RetryPolicy(attempts=1)
bot = Telegram(token=os.environ["TELEGRAM_BOT_TOKEN"], retry=once)retry= и timeout= принимают все HTTP-клиенты (Facebook, Instagram, LinkedIn, TikTok, Telegram, Ads), а также их from_env() и Instagram.via_facebook(). Политика задаётся для каждого клиента отдельно — глобальной настройки нет.
Рекомендуемая обработка: четыре случая
Когда повторы исчерпаны, ошибка доходит до вашего кода. Ниже — шаблон для фоновой задачи.
import logging
from socialift import ApiError, AuthError, RateLimitError, TransportError
from socialift import PermissionError as ScopeError
log = logging.getLogger("app")
async def sync_profile(ig, account, jobs):
# account и jobs — объекты вашего приложения (запись в БД и очередь задач)
try:
return await ig.profile(account.token, ig_user_id=account.ig_user_id)
except AuthError:
account.needs_reconnect = True # отправьте пользователя в OAuth заново
except ScopeError as exc:
log.error("Не хватает разрешений: %s", exc) # scope или App Review — повтор бесполезен
except RateLimitError as exc:
await jobs.retry_later(account.id, delay=exc.retry_after or 300)
except TransportError:
await jobs.retry_later(account.id, delay=30)
except ApiError as exc:
log.error("%s status=%s code=%s", exc.provider, exc.status, exc.code)Порядок except важен: AuthError, PermissionError и RateLimitError — наследники ApiError, поэтому идут раньше.
SDK не обновляет истёкший токен сам. Методы обновления: Instagram.refresh_token (Instagram Login), TikTok.refresh_token, LinkedIn.refresh; при отозванном токене пользователь входит заново.
Чек-лист по обработке ошибок
- Не повторяйте
AuthErrorиPermissionError— они требуют переподключения или исправления настроек. - Если у
RateLimitErrorнетretry_after, ставьте задачу в очередь с задержкой в минутах. - Для логов используйте
str(exc),exc.status,exc.codeиexc.payload. Не пишите в логexc.url: в запросах Meta там есть query-параметрaccess_token. - Перехватывайте
LicenseErrorотдельно отApiError— это проблема лицензии, а не платформы. ConfigurationError— ошибка в коде или переменных окружения; выявляйте её при старте.
Частые вопросы
Сколько ждать, если у RateLimitError retry_after равен None?
Для Meta это обычная ситуация: стандартный заголовок Retry-After для лимитов Meta не документирует. Выберите задержку сами (например, несколько минут) и перезапустите задачу через очередь. Встроенные повторы SDK измеряются секундами и не рассчитаны на выход из длительного лимита.
Обновляет ли SDK токен сам после AuthError?
Нет. SDK не хранит токены и не обновляет их автоматически. Обновить токен до истечения срока или отправить пользователя в OAuth заново — задача вашего приложения. TokenBundle.is_expiring() помогает понять, когда пора обновлять.
Почему PermissionError не проходит при повторе?
Потому что причина не в запросе, а в разрешениях: нужный scope не запрошен, приложение не прошло проверку платформы (например, Meta App Review) или в чате Telegram нет прав. Исправьте настройки и переподключите пользователя с нужными разрешениями.
Можно ли полностью отключить повторы?
Да: передайте клиенту retry=RetryPolicy(attempts=1). Тогда любая ошибка поднимается сразу после первой попытки. Это полезно для операций, где повтор опасен, — публикации поста или отправки сообщения.
Где взять код ошибки TikTok?
TikTok возвращает строковый код (например, access_token_invalid). SDK превращает его в класс, но не записывает в exc.code: исходный код лежит в exc.payload, а log_id, который запрашивает поддержка TikTok, добавлен в текст сообщения.
Чем TransportError отличается от ApiError?
ApiError — платформа ответила, но ошибкой: есть status и часто code. TransportError — ответа не было вовсе (обрыв, DNS, таймаут), поэтому status нет. TransportError повторяется автоматически, а ApiError — только при лимите, 429 и 5xx.