Health
Вкладка Health — линтер времени выполнения для проблем, которые постоянно всплывают в issues effector. Каждый пункт говорит, что случилось, где (ссылка на файл открывает панель Sources на нужной строке) и как это исправить.


Как читать список
Пункты отсортированы по уровню: ошибки (красный !), предупреждения (жёлтый !), информация (i) и пройденные проверки (✓). На ярлыке вкладки — число ошибок, а если их нет — предупреждений.
×3 · последний #8— сколько раз это случилось и последняя транзакция;- клик по пункту открывает транзакцию в логе (или стор в Stores);
- Показать в Graph фокусируется на причастных юнитах (циклы, устаревшее чтение, двойные обновления, запись в производные сторы, аварийная остановка);
- Проверить производные сторы (вверху вкладки) запускает проверку согласованности по запросу.
Пункты, которые происходят из транзакций, очищаются вместе с логом; пункты о юнитах и scope остаются.

Проверки по транзакциям
Вызов вне scope
Ошибка · Вызов вне scope: greetingShown
Юнит вызван вне scope, хотя приложение использует fork(). Изменение ушло в глобальный граф, а приложение читает свой scope и его не видит. Обычно это вызов из setTimeout, сокета, стороннего колбэка или прямой вызов вместо useUnit. Строка в логе красная, с бейджем вне scope.
Исправление: привяжите вызов до выхода из эффекта — const fn = scopeBind(greetingShown) — или вызывайте через useUnit.
Обновлён больше одного раза за транзакцию
Предупреждение · $errors обновлён больше одного раза за транзакцию
Стор пересчитался дважды за один проход. effector упорядочивает шаги combine и sample по порядку объявления, а не по графу, поэтому потребитель, объявленный раньше источников, сначала читает старое значение. В логе — бейдж 2× $errors.
Исправление: объявите стор после юнитов, которые его питают, или соберите его через combine вместо цепочки sample.
Остановлен filter
Информация · sample(…) остановлен filter
filter вернул false, target не вызван. Само по себе не ошибка — но когда кнопка «ничего не делает», причина обычно здесь. Откройте транзакцию, чтобы увидеть значения source и filter.
Исключение в чистой функции
Ошибка · Исключение в $divisor.map → $divisor → *
Бросил редьюсер, map, combine или filter. effector пишет ошибку в консоль и останавливает только эту ветку: соседние ветки уже применились, поэтому производные сторы могут разойтись с источниками. В подробностях перечислено, что не выполнилось из-за исключения.
Исправление: редьюсеры и функции маппинга должны быть чистыми и не бросать исключений; рискованный код — в эффект.
Прочитал до обновления (устаревшее чтение)
Предупреждение · sample($price, $qty → totalLogged) прочитал $qty до обновления

В той же транзакции стор изменился после того, как sample взял значение, поэтому sample использовал старое. effector упорядочивает sample по объявлению и приоритету, а не по потоку данных.
Исправление: запускайте sample от этого стора (clock: $qty) или объявите его после юнитов, которые обновляют стор.
Запись в производный стор
Предупреждение · В производный стор $x пишут напрямую
Стор из map/combine получил значение от sample или события. В effector это устарело: следующее обновление источников перезапишет значение, а до этого стор и источники расходятся.
Исправление: сделайте его обычным стором (createStore + .on / sample) или пишите в его источники.
Эффект завершился ошибкой
Информация · signupFx завершился ошибкой
Эффект завершился с ошибкой; в подробностях — её сообщение. Помогает заметить сбои, которые UI молча проглатывает.
Возможный бесконечный цикл
Ошибка · Возможный бесконечный цикл от loopStart
Одна транзакция выполнила больше maxSteps шагов (по умолчанию 5000), и её дерево шагов обрезано. Синхронный цикл через события не останавливается и вешает вкладку; цикл через сторы останавливается, когда значение перестаёт меняться.
Исправление: откройте Graph и найдите цикл, который проходит только через события.
deffector остановил бесконечный цикл
Ошибка · deffector остановил бесконечный цикл
Один синхронный проход ядра превысил hardStop шагов (по умолчанию 100 000). deffector оборвал распространение, чтобы вкладка не зависла: каждый узел, выполненный сверх лимита, перестаёт передавать значения дальше, ядро опустошает очередь, а на следующей микрозадаче связи возвращаются. Состояние может быть обновлено частично; транзакция помечена остановлено. В подробностях — юниты, которые выполнялись чаще всего.
Исправление: найдите цикл в Graph (он проходит через эти юниты) и разорвите его filter-ом или вынесите вызов из watcher. См. Производительность.
Зацикливаний нет
Пройдено · Зацикливаний нет — ни одна транзакция не выполнила больше maxSteps шагов.
Проверки юнитов и scope
Сторы без sid
Предупреждение · У 3 из 20 сторов нет sid
Без sid serialize(scope) молча пропускает стор, гидрация до него не доходит, а записанный трейс сопоставит его только по имени. Перемещение во времени в пределах страницы работает.
Исправление: подключите effector/babel-plugin или @effector/swc-plugin для этих файлов.
Повторяющийся sid
Ошибка · Повторяющийся sid 2r0u4d|xz7n29
У нескольких юнитов один sid: serialize, гидрация и подмена хендлеров их перепутают. Обычно фабрика не указана в factories плагина или плагин применён дважды. (Юниты, созданные заново после старта, показываются как утечка.)
Исправление: добавьте фабрику в опцию factories плагина.
Глобальный режим
Предупреждение · Глобальный режим: нет fork()
Приложение работает с глобальным графом. Перемещение во времени записывает значения на месте через launch: watchers, sample и эффекты на это реагируют, поэтому результат не гарантирован. Воспроизведение подменяет хендлеры эффектов глобально.
Исправление: лучше использовать fork() и рендерить приложение внутри <DeffectorProvider value={scope}>.
Scope без адаптера
Предупреждение · Используется scope, но приложение не обёрнуто в DeffectorProvider
Без адаптера deffector не может показать scope из прошлого, поэтому переход записывает значения в живой scope на месте.
Исправление: замените Provider из effector на DeffectorProvider из @deffector/agent/react (или /vue, /solid).
Значения с сервера без стора
Предупреждение · 2 значени(й) с сервера не нашли стор на клиенте
fork({ values }) или гидрация получили sid, которых нет на клиенте. Либо сервер и клиент собирают модель по-разному (опции плагина, factories), либо модуль ещё не загружен. Попробуйте в демо-лаборатории с ?hydrate.
Исправление: используйте одинаковую конфигурацию babel/swc-плагина на сервере и клиенте; перечислите фабрики в опциях плагина.
Создан N раз
Предупреждение · $field создан 12 раз
Юниты из одного и того же места в коде снова и снова создаются после старта приложения. Юниты, созданные в компоненте, watcher-е или эффекте, не собираются сборщиком мусора и ломают SSR (каждый раз новые sid). Сообщается, когда одно место создало юниты хотя бы трижды.
Исправление: создавайте модель один раз на уровне модуля или держите экземпляр фабрики вне рендера (useMemo не спасает в StrictMode).
Юниты, созданные после старта
Информация · 14 юнит(ов) создано после старта
Перечисляет файлы, которые создавали юниты после старта приложения. Лениво загруженные чанки делают это один раз, это нормально; повторное создание показывается отдельно, как выше.
Цикл только через события
Предупреждение · Цикл только через события: loopStart → loopNext → …
Найден в статическом графе: события вызывают друг друга без стора между ними. Если filter его не остановит, один вызов зациклится и повесит вкладку.
Исправление: добавьте filter или проведите цикл через стор (стор останавливается, когда значение перестаёт меняться).
Цикл через стор
Информация · Цикл через стор: clamp → $clamped → …
Заканчивается, когда значение стора перестаёт меняться. Для сходящейся логики это нормально; если значение каждый раз новое (счётчик, новый объект), цикл идёт до лимита шагов.
История до открытия панели
Информация · История до открытия панели не записана
Агент стоит на паузе, пока DevTools закрыты: первые 10 с после загрузки (graceMs) он пишет, поэтому DevTools можно открыть и перезагрузить страницу — начало сохранится.
Исправление: откройте DevTools и перезагрузите страницу, чтобы записать с самого начала, или задайте attachDeffector({ whileClosed: 'record' }).
Другой инструмент перехватил инспектор
Ошибка · Другой инструмент перехватил инспектор effector
В effector один слот инспектора. effector/inspect (его используют effector-logger и @effector/redux-devtools-adapter) загрузился после deffector и заменил его: новые транзакции не записываются. Пока панель открыта, deffector проверяет слот каждые несколько секунд.
Исправление: уберите другой инструмент в разработке или импортируйте его до @deffector/agent. Кнопка Вернуть у пункта забирает слот обратно.
Производные сторы разошлись с источниками
Проверить производные сторы пересчитывает каждый производный стор из текущих значений записываемых сторов во временном fork() и сравнивает результат с тем, что хранит приложение.
- Пройдено ·
Производные сторы совпадают с источниками; - Предупреждение ·
2 производн(ых) стор(ов) разошлись с источниками— обычно после исключения вmap/combineили прямой записи в производный стор. Исправление: посмотрите последнюю транзакцию с ошибкой и исправьте функцию, которая бросает исключение.
Проверка запускается по запросу, потому что ещё раз выполняет все производные вычисления. Она есть и в палитре команд.