MAATRIX / Блог / Jupyter на сервере: частые ошибки и решения

Jupyter на сервере: частые ошибки и решения

Jupyter на сервере: частые ошибки и решения

MAATRIX

Jupyter на сервере поднят и вроде бы работает — а потом тетрадь отказывается открываться с чем-то про JSON, диск внезапно кончается, или ядро умирает раньше, чем успевает поздороваться с интерфейсом. Это не про установку — про то, что случается с уже работающим Jupyter спустя недели реальной эксплуатации. Если сервис ещё не развёрнут, начните со статьи об установке Jupyter на VPS; здесь — разбор частых ошибок Jupyter, которые всплывают уже после, с точными текстами из логов и командами восстановления.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Тетрадь не открывается: `NotJSONError` и как вернуть содержимое после обрыва записи

Шесть симптомов ниже выглядят по-разному, но у каждого свой точный текст в логе — узнали случай, сразу переходите в нужный раздел:

СимптомПричинаГде искать
nbformat.reader.NotJSONError при открытииобрыв записи .ipynb на серединеэтот раздел
OSError: [Errno 28] No space left on deviceчекпойнты и base64-вывод ячеек забили дискраздел 2
Kernel died before replying to kernel_infoверсии ipykernel/jupyter_client разошлись в venv ядрараздел 3
Жёлтая полоса «Build recommended», старый интерфейскэш сборки JupyterLab не обновилсяраздел 4
Виджет не рисуется, ошибки в логе нетipywidgets и jupyterlab_widgets разных линийраздел 5
Start request repeated too quickly в journalctlsystemd остановил юнит после серии быстрых паденийраздел 6

Самый неприятный из них — сама тетрадь перестаёт открываться. Jupyter показывает диалог с ошибкой чтения, а в логе сервера — что-то в духе nbformat.reader.NotJSONError: Notebook does not appear to be JSON. Причина почти всегда механическая: запись .ipynb на диск прервалась на середине — по OOM, по kill -9, по разрыву соединения при сохранении, — и файл остался с недописанным JSON.

Первым делом проверьте файл напрямую, в обход Jupyter:

python3 -c "import json; json.load(open('analysis.ipynb'))"

Ответ вида json.decoder.JSONDecodeError: Expecting ',' delimiter: line 842 column 3 (char 30211) — не приговор, а точная координата обрыва: файл читаем до этой строки, значит, основная часть тетради жива.

Два пути восстановления:

  • Чекпойнт. При каждом явном сохранении Jupyter кладёт зеркальную копию рядом, в .ipynb_checkpoints/<имя>-checkpoint.ipynb. Если она создана до сбоя — это и есть рабочая версия: cp .ipynb_checkpoints/analysis-checkpoint.ipynb analysis.ipynb.
  • Ручная починка, если чекпойнт тоже битый или его нет. Notebook — это JSON-массив ячеек, и файл, оборванный на середине, почти всегда не хватает только закрывающих скобок в конце. Откройте файл текстовым редактором до координаты из ошибки, посчитайте открытые {/[, допишите столько же закрывающих в конце — в подавляющем большинстве случаев тетрадь снова читается, теряется только последняя незаписанная ячейка, а не всё остальное.

Дальше — откуда чаще всего берётся сам обрыв записи; разбор в следующем разделе.

Диск кончился внезапно: `No space left on device`, чекпойнты и ячейки с графиками

Продолжение предыдущей причины: сохранение обрывается не только от OOM, но и когда на диске физически не осталось места — сервер отвечает OSError: [Errno 28] No space left on device, и именно в этот момент велик шанс получить битый файл из раздела выше.

Датасеты обычно не главный виновник — их отдельно видно в du. Настоящая утечка места специфична для Jupyter и легко ускользает от внимания:

  • каждый вывод ячейки — график matplotlib, картинка, HTML-таблица — сохраняется внутри .ipynb как base64-текст; тетрадь с полусотней графиков за месяцы работы легко доходит до нескольких десятков мегабайт;
  • каждое явное сохранение дублирует файл в .ipynb_checkpoints/ — то есть один и тот же объём хранится дважды;
  • кэш пакетов растёт молча: ~/.cache/pip на сервере, где часто ставят и удаляют библиотеки, спокойно набирает гигабайты за месяцы.

Найти, где именно место:

df -h /
du -sh ~/.cache/pip ~/.local/share/jupyter 2>/dev/null
find ~/notebooks -name "*.ipynb" -size +10M -exec ls -lh {} \;

Разгрузка раздутой тетради — не удалять код, а очистить сохранённый вывод:

jupyter nbconvert --clear-output --inplace analysis.ipynb

Файл на диске резко худеет, код и текст остаются на месте — просто при следующем запуске графики придётся перерисовать. Кэш pip чистится отдельно: pip cache purge.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

`Kernel died before replying to kernel_info`: ядро не стартует после апгрейда одного пакета

Отличается от обычного падения посреди работы: здесь ядро не запускается вовсе, сразу после выбора ноутбука. Jupyter покажет короткое Kernel died before replying to kernel_info и почти никаких подробностей — интерфейс намеренно прячет полный traceback, показывая только факт смерти процесса.

Типичная причина — частичный апгрейд: pip install -U jupyterlab (или отдельно ipykernel, jupyter_client) в уже работающем venv меняет одну версию, а смежные пакеты остаются старыми. Ядро падает при импорте раньше, чем успевает ответить на первый же протокольный запрос.

Чтобы увидеть настоящую ошибку, запустите команду старта ядра руками — она лежит в kernel.json того самого окружения:

jupyter kernelspec list
cat /home/user/.local/share/jupyter/kernels/project/kernel.json

Первый элемент массива argv — это точный путь до интерпретатора и модуля ipykernel_launcher. Скопируйте всю команду из argv и выполните в терминале как есть: Jupyter скрывает traceback, а голый запуск — нет. Увидите настоящую причину, обычно ImportError: cannot import name X from Y или AttributeError из-за разошедшихся версий.

Лечится приведением версий к одной точке в пределах именно этого окружения ядра:

/opt/projects/ml/venv/bin/pip install -U --force-reinstall ipykernel jupyter_client

Важно: команда должна идти в venv именно этого ядра, а не в общий venv Jupyter-сервера — это разные окружения, и путаница между ними уже разбиралась в статье про установку применительно к ModuleNotFoundError.

Белый экран и «Build recommended»: расширения и кэш JupyterLab

После установки расширения через pip install jupyterlab-git (или похожий пакет) интерфейс либо не меняется, либо наверху всплывает жёлтая полоса «Build recommended». В JupyterLab 3 с этим приходилось мириться регулярно: сборка шла через Node.js и jupyter lab build, и без nodejs/npm на сервере она падала сразу же.

В JupyterLab 4 это в основном позади: расширения ставятся как «federated» — уже собранный JS-бандл лежит прямо внутри pip-пакета, отдельная сборка обычно не нужна. Проверка, что расширение реально встало и включено:

jupyter labextension list

В выводе — имя, версия и статус enabled OK. Если disabled, error или расширения нет вовсе — снова тема окружений, но применительно к серверу, а не к ядру: sudo -u jupyter /opt/jupyter/venv/bin/pip show jupyterlab-git покажет, стоит ли пакет там, где его реально ищет процесс.

Если список чистый, а интерфейс всё равно не обновился — дело в кэше статики браузера или самого JupyterLab. Сначала жёсткое обновление страницы (Ctrl+Shift+R); если не помогло — очистка и пересборка на сервере:

jupyter lab clean --all
jupyter lab build

clean --all стирает каталоги staging и static под share/jupyter/lab, build пересобирает их заново. Для чисто federated-расширений на сервере без Node.js эта команда почти никогда не требуется — но полезно знать, что она есть, когда интерфейс застрял на старой версии после апгрейда.

Слайдер не рисуется: `ipywidgets` без ошибки, но и без виджета

import ipywidgets as widgets; widgets.IntSlider() в ячейке — и вместо ползунка либо пусто, либо текст Error displaying widget: model not found. Ошибки в терминале нет, ядро живо — типичный признак, что клиентская и серверная половины виджета разошлись по версии.

У ipywidgets две независимые части: Python-пакет живёт в окружении ядра — там, где вы пишете import ipywidgets, а JS-часть, пакет jupyterlab_widgets, — в окружении самого JupyterLab-сервера. Та же ловушка, что и с ModuleNotFoundError в статье об установке, только тоньше: jupyter labextension list честно покажет jupyterlab_widgets включённым и корректным, а виджет всё равно не отрисуется — сломана как раз половина в венве ядра.

Проверка версий с двух сторон:

/opt/projects/ml/venv/bin/pip show ipywidgets
/opt/jupyter/venv/bin/pip show jupyterlab_widgets

Рабочая пара — ipywidgets восьмой линии с jupyterlab_widgets третьей линии; смешение восьмой с более старой второй линией — самая частая причина именно пустого места вместо контрола. Обновлять нужно ту сторону, где версия отстала, и после установки обязательно перезапустить ядро — на лету JupyterLab такое обновление не подхватывает.

`Start request repeated too quickly`: systemd сдаётся раньше, чем вы находите причину

Если Jupyter уже оформлен systemd-юнитом (разбор — в статье про установку), с Restart=on-failure он честно пытается подняться после падения. Но у systemd есть встроенный предохранитель: слишком много попыток за короткое время — и он останавливается сам, не дожидаясь вмешательства.

systemctl status jupyter
Active: failed (Result: exit-code)
journalctl -u jupyter -n 20 --no-pager
jupyter.service: Start request repeated too quickly.
jupyter.service: Failed with result 'exit-code'.

Это не шестая причина падений сама по себе — это systemd, который после нескольких быстрых падений подряд (по умолчанию около пяти за десять секунд) перестаёт перезапускать юнит и фиксирует его как failed. Механизм рассчитан на мгновенно повторяющиеся сбои — опечатку в конфиге, отсутствующий файл, проблему с правами, — а не на что-то вроде OOM, случающегося раз в дни.

Работать с этим нужно в правильном порядке. Сначала — не перезапуск, а причина: journalctl -u jupyter -n 100 --no-pager и ищите первую запись о падении, а не последнюю — именно в ней настоящий Python-traceback, дальше идут уже однотипные повторы без деталей. Частый виновник — синтаксическая опечатка в jupyter_server_config.py, которая рушит процесс на импорте конфига ещё до старта веб-сервера.

После того как причина исправлена, недостаточно просто systemctl start — счётчик неудачных попыток нужно сбросить явно:

systemctl reset-failed jupyter
systemctl start jupyter

Без reset-failed systemd может отказать в старте ещё раз, хотя причина уже устранена, — со стороны выглядит так, будто исправление не помогло.

Какой сервер под Jupyter брать в MAATRIX

Причины выше — не про нехватку мощности в моменте, а про то, что копится за недели работы сервера: диск съедают чекпойнты и вывод ячеек, память — незакрытые вовремя ядра, systemd — мелкие сбои конфига. Отсюда и логика конфигурации: запас не только под датасет на старте, а под то, что накопится.

По диску — практическое правило из раздела про заполнение: закладывайте на чекпойнты и вывод ячеек 30–50% сверх размера самих датасетов, а не впритык. NVMe на 60–80 ГБ вместо ровно посчитанных под данные 40 ГБ снимает разом и панику из-за No space left on device, и риск получить битый .ipynb в момент, когда места не хватило ровно на середине записи.

По памяти — раздел про зомби-ядра из статьи об установке уже решает регулярную утечку через cull_idle_timeout, но между циклами уборки память всё равно занята, а второе-третье открытое ядро с датафреймом добавляется поверх первого. 4 ГБ комфортны для одного человека с несколькими проектами, 8 ГБ снимают вопрос совсем, если ноутбуков параллельно открыто больше двух-трёх.

Локация — Великобритания, Лондон, тот же выбор, что и для самой установки: сервер стабильно достаёт PyPI, conda-forge и Hugging Face без региональных сюрпризов, а для команды в Европе или России плечо короче, чем через США или Азию.

Честно про установку: Jupyter не входит в каталог готовых приложений apps.maatrix.io — сервер приезжает чистым, с Ubuntu 24.04 или Debian, а сам сервис поднимается по инструкции из статьи об установке; готовые сборки в каталоге уже есть для соседних инструментов дата-стека, но не для самого Jupyter. Эта статья — про то, что происходит дальше, когда он уже работает. Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT: иностранная карта не нужна, хотя сервер физически в Лондоне.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Тетрадь совсем не открывается, Jupyter жалуется на JSON — это потерянные часы работы?

Почти никогда не полностью. Notebook — это JSON-массив ячеек, и обрыв записи обычно режет только хвост файла. Сверьте координату из json.decoder.JSONDecodeError, попробуйте копию из .ipynb_checkpoints/, а если её нет — дописать недостающие закрывающие скобки в конце файла руками почти всегда возвращает всё, кроме последней несохранённой ячейки.

После pip install -U jupyterlab перестало запускаться конкретное ядро проекта — при чём тут вообще JupyterLab?

Апгрейд одного пакета венва тянет за собой связанные — jupyter_client, ipykernel — и если они разошлись по версии именно в венве ядра, а не сервера, ядро падает на импорте раньше первого ответа. Запустите команду из argv в kernel.json руками — она покажет настоящий traceback, который сам Jupyter в интерфейсе прячет.

systemctl start jupyter не запускает сервис, хотя конфиг я уже поправил — почему?

Systemd после нескольких быстрых падений подряд фиксирует юнит как failed и перестаёт пробовать сам, даже когда причина уже устранена. Сначала systemctl reset-failed jupyter, потом systemctl start jupyter — без сброса счётчика повторный старт может не сработать.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.