Jupyter на сервере: частые ошибки и решения
Jupyter на сервере поднят и вроде бы работает — а потом тетрадь отказывается открываться с чем-то про JSON, диск внезапно кончается, или ядро умирает раньше, чем успевает поздороваться с интерфейсом. Это не про установку — про то, что случается с уже работающим Jupyter спустя недели реальной эксплуатации. Если сервис ещё не развёрнут, начните со статьи об установке Jupyter на VPS; здесь — разбор частых ошибок Jupyter, которые всплывают уже после, с точными текстами из логов и командами восстановления.
Содержание
- Тетрадь не открывается: `NotJSONError` и как вернуть содержимое после обрыва записи
- Диск кончился внезапно: `No space left on device`, чекпойнты и ячейки с графиками
- `Kernel died before replying to kernel_info`: ядро не стартует после апгрейда одного пакета
- Белый экран и «Build recommended»: расширения и кэш JupyterLab
- Слайдер не рисуется: `ipywidgets` без ошибки, но и без виджета
- `Start request repeated too quickly`: systemd сдаётся раньше, чем вы находите причину
- Какой сервер под Jupyter брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество 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 в journalctl | systemd остановил юнит после серии быстрых падений | раздел 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 — десятки моделей в одном окне. Оплата картой РФ и по СБП.