Ответ телеметрии в 27 байт вешает Claude Desktop на Linux

Claude Desktop на Linux зависает из-за телеметрии, ответ на которую приложение не читает, показал в разборе от 13 ноября автор блога Dfb. Chromium держит под каждый такой ответ в 27 байт открытый файловый дескриптор, и примерно через тысячу ответов процесс страницы упирается в лимит 1024. Если приложение у вас встаёт так же, в наших прогонах на голом Electron зависание отодвигал запуск с повышенным мягким лимитом открытых файлов (для самого Claude Desktop это наш вывод, не замер), а саму утечку закрывает одна строка в коде приложения.
Причину автор искал два месяца и нашёл в дампе памяти на 1,5 ТиБ, снятом с зависшего процесса после 35 часов работы. «Раз в два дня» - округление: сам автор пишет, что падения нерегулярны, и между сбоями, которые он ловил, проходило 11, 13, 2 и 8 дней. Всё это наблюдения одного пользователя на его машине.
Как дожить до исправления
Мягкий лимит дескрипторов процесс страницы наследует от того, что запустило приложение. В наших прогонах с ulimit -Sn 4096 в запускающей оболочке страница с той же утечкой прошла все 1 100 запросов на трёх версиях Electron и закончила с 1132-1134 открытыми дескрипторами: утечка остаётся, сдвигается только потолок. С этим сходятся чужие отчёты в другом issue о той же утечке, заведённом другим пользователем 1 октября и всё ещё открытом. В комментариях там пишут, что Claude Desktop 3.1623.4 поднял лимит процесса страницы до 524 288 и зависания прекратились, а 4.23118.0 вернул 1024.
Правка в приложении - дописать после fetch .then(r => r.body?.cancel()) или слать сброс через navigator.sendBeacon. На Electron 44.9.3 оба варианта, как и чтение тела через r.text(), у нас довели 1 100 запросов до конца при 32 дескрипторах. Закрыть утечку можно и с сервера: ответ с no-store без тела или с кодом 204, как и ответ без Cache-Control, дескрипторы не копил. Проверяли мы это на своём локальном сервере, не на эндпоинте Anthropic.
Ловушка не только для Claude: в Chromium любой отправленный и забытый fetch, на который пришёл непустой ответ с no-store, держит дескриптор, пока тело не прочитают или не отменят. Автор бага в Chromium, открытого ещё в 2024 году, писал в комментариях: «Многие веб-приложения запрашивают через голый fetch() непустой ответ с no-store и никогда его не читают».
Почему дескриптор не закрывается
Когда окно скрыто или простаивает, вкладка Code отправляет POST на /v1/code/channels/<id>/client/presence с "clear":true, сообщая серверу, что пользователя нет. Запрос уходит с keepalive: true, ошибки глушит .catch(()=>{}), а ответ {"refresh_after_seconds":0} никто не читает. Обычный запрос присутствия своё тело читает через r.json(), пропускает его только сброс.
Тело ответа Chromium передаёт процессу страницы через регион разделяемой памяти на 2 МиБ, и каждый регион - один дескриптор. Обычно Blink, движок рендеринга Chromium, вскоре вычитывает тело в память, но для ответов с Cache-Control: no-store этот шаг пропускается. Свежий процесс, по замеру автора, набирал 45 таких регионов в час; в дампе их было 942, и в 938 лежал один и тот же ответ в 27 байт.
Сначала автор подозревал встроенный в приложение браузерный SDK Datadog, который держал 801 такой Response в своём реестре запросов. Но в репро без сохранённых ссылок сборщик мусора собрал все 800 объектов Response, а 836 дескрипторов остались открытыми: Chromium не закрывает канал вместе с объектом.
У процесса страницы мягкий лимит 1024 дескриптора, браузерный процесс поднимает свой до 524 288. Когда дескрипторы кончаются, ядро не может доставить дескриптор, приложенный к сообщению, а Mojo, межпроцессный транспорт Chromium, в релизной сборке Chrome 152 этого не проверяет. Сообщение приходит без дескриптора, канал ждёт его бесконечно, и всё, что идёт следом, застревает. В Chrome 154 зависание исправили: с keepalive-запросами процесс страницы завершается с кодом 0, но страница по-прежнему не получает никакой ошибки.
«Работает как задумано»
Владелец того бага в Chromium, у которого приоритет P3, ответил так: «Если вы можете прочитать Response, но решаете этого не делать, думаю, всё работает как задумано. Браузер не может знать, что вы не прочитаете ответ позже, поэтому должен его держать». Отдельный баг автора с просьбой отклонять fetch() с TypeError, когда дескриптор получить нельзя, в тот же день закрыли как дубликат.
Issue автора в репозитории Anthropic бот через 50 секунд после подачи пометил как invalid, а через три дня закрыл с пояснением: «Пока закрываем: похоже, это не про Claude Code». Запрос при этом шлёт вкладка Code, а она, как замечает автор, и есть Claude Code.
Авторский разбор
Что мы проверили
14 ноября мы прогнали репро автора на голом Electron 44.9.3, 45.2.3 и 46.0.0-alpha.10 (Chrome 152, 156 и 159; arm64, --no-sandbox) и разобрали новейший пакет Claude Desktop из apt-репозитория Anthropic. Само приложение мы не запускали.
Утечка воспроизводится, как описал автор: страница встаёт, когда процесс упирается в 1024 дескриптора, и 993 из них занимают непрочитанные ответы. Обе его правки утечку закрывают. Устарело одно: официальная сборка уже на более новом Chromium, где в наших прогонах процесс страницы вместо зависания молча завершался.
- В контейнере с
/dev/shmна 64 МБ, как по умолчанию в Docker, Electron 44.9.3 упёрся раньше: после 30 непрочитанных ответов следующие fetch отклонялись сTypeError: Failed to fetch, 1 070 из 1 100 в одном прогоне. Ту самую ошибку автор и просил у Chromium. На 45.2.3 регионы лежат в memfd, и этот потолок не действует. - Автор пишет, что Claude Desktop всё ещё на Chrome 152: его дамп снят с версии 4.16336.0 на Electron 44.9.3. Пакет 5.11492.5, выложенный в репозиторий Anthropic 14 ноября, собран на Electron 45.2.1 с Chrome 156.0.8078.75, а сброс присутствия в нём прежний, без
cancel(), хотя фронтенд приложение, по словам автора, грузит с claude.ai, и в работе может быть другой код. - На Electron 45.2.3 и 46.0.0-alpha.10 процесс страницы после «fetched 900» у нас завершался с кодом 0 и с keepalive, и без него (без keepalive по три прогона на версию), хотя у автора без keepalive страница жила дальше; условия у нас другие. Отсюда наш вывод, не замер: на текущей сборке Claude Desktop скорее стоит ждать тихого выхода процесса страницы, чем зависания.
Дальше
Anthropic подали в суд из-за названия модели Mythos
Иск о нарушении прав на товарный знак, по данным Reuters, получила Anthropic, и спор идёт вокруг названия модели Mythos. Претензия касается именно имени, под которым Anthropic выпускает модель. Перед запуском своего продукта вы проверяете название по реестру товарных знаков?
Читайте также
- Claude Code шлёт Anthropic хеши файлов даже с DeepSeek
- Разбор Claude Desktop: MCP-сервер работает вне песочницы
- Ранние замеры: утром в США Claude дороже примерно в 1,4 раза
- Claude Opus 5.5 прошёл Baldur's Gate 3 сам за 39 часов
- Хакатон Claude Code в Японии ждёт и тех, кто не пишет код
- Шифр золотых слитков не вскрыли, потому что шифра нет
Комментарии
Пока никто не написал. Будьте первым.
Присоединяйтесь к разговору
Войдите, чтобы оставить комментарий. Он появится после модерации.

