0% прочитано

Vite EACCES у Laravel: чому node_modules/.vite стає власністю root і як це виправити

Під час локальної роботи з Laravel і Vite я отримала EACCES: permission denied для node_modules/.vite/deps/package.json. Причина виявилася не у Vite, а у власнику файлів: частину кешу раніше створив root через Docker або команду з sudo. Розбираю, як знайти такі файли, коли достатньо видалити .vite, коли потрібно виправити ownership усього node_modules і як не повторити проблему в Laradock.

12 вересня 2026 р. 9 хв читанняLaradock

Під час локальної роботи з Laravel і Vite у ICanUp я отримала помилку, яка спочатку виглядала як проблема самого Vite.

Dev server намагався оновити свій кеш у node_modules/.vite, але не міг видалити один із файлів.

Причина виявилася простішою: файл був створений іншим системним користувачем і поточний користувач не мав права його змінювати.

Помилка, з якої все почалося
Error: EACCES: permission denied, unlink'node_modules/.vite/deps/package.json'
EACCES у цьому випадку не означав пошкодження Laravel або npm package. Vite просто не мав filesystem permission для файла, який йому потрібно було перегенерувати.
Vite cache becomes root-owned after Docker or sudo and later fails with EACCES for the normal project user
Проблема виникає, коли один процес створює node_modules/.vite від root, а наступний запуск Vite виконується від звичайного користувача.

Спочатку я перевірила не Vite, а власника файлів

Коли в повідомленні є EACCES, найкорисніше спочатку подивитися на файлову систему.

Не потрібно одразу перевстановлювати весь frontend або міняти Vite config.

BASH - Перевірити власника і права
ls -ld \  node_modules \  node_modules/.vite \  node_modules/.vite/deps stat -c '%U:%G %a %n' \  node_modules \  node_modules/.vite \  node_modules/.vite/deps \  node_modules/.vite/deps/package.json

Якщо проєкт належить моєму звичайному користувачу, а всередині node_modules/.vite раптом з'являється root:root, причина практично вже знайдена.

Чому root-owned файл взагалі з'являється в node_modules

Найчастіше такий стан виникає не під час звичайного npm run dev, а після змішування різних способів запуску Node.

Наприклад, один раз Vite запустили через контейнер від root або через sudo, а наступного разу - від звичайного користувача на host.

  • Vite або npm запускали через sudo.
  • Docker container працював від root і писав у bind-mounted project directory.
  • Залежності встановлювалися одним користувачем, а dev server запускався іншим.
  • Host Node і container Node по черзі використовували той самий node_modules без узгодженого UID/GID.
Як виникає конфлікт користувачів
First run: root  |  vnode_modules/.vite/deps/package.jsonowner = root  Next run: alyona  |  vVite tries to unlink package.json  |  vEACCES

Що саме Vite зберігає в node_modules/.vite

Каталог node_modules/.vite не є моїм application source code.

Vite використовує його для згенерованого кешу і попередньо оброблених залежностей, щоб наступні запуски dev server були швидшими.

Тому видалення .vite не видаляє код застосунку або встановлені package definitions. Vite може створити цей кеш знову.

Шлях

Роль

Можна перегенерувати

resources/

Код застосунку

Ні

package.json

Опис залежностей і scripts

Ні

package-lock.json

Зафіксовані версії залежностей

Ні

node_modules/.vite

Згенерований кеш Vite

Так

Якщо проблема тільки в .vite, не потрібно чіпати весь node_modules

Я починаю з найменшого можливого виправлення.

Якщо node_modules загалом належить правильному користувачу, а проблема обмежена Vite cache, достатньо прибрати цей кеш і дати Vite створити його заново.

BASH - Перегенерувати Vite cache
rm -rf node_modules/.vite npm run dev
Якщо сам каталог .vite належить root і поточний користувач не може видалити його вміст, звичайний rm також завершиться з permission denied. Тоді root потрібен тільки для одноразового очищення вже неправильних файлів, а не для запуску Vite.
BASH - Одноразово видалити root-owned cache
sudo rm -rf node_modules/.vite npm run dev

Тут є важлива різниця: sudo використовується лише для видалення вже створеного root-owned кешу.

Новий npm run dev я запускаю без sudo.

Коли видалення .vite вже недостатньо

Іноді проблема не обмежується одним кешем.

Якщо npm install або інший Node process раніше працював від root, root-owned файли можуть бути розкидані по всьому node_modules.

BASH - Знайти root-owned файли в node_modules
find node_modules \  -user root \  -print \  | head -n 50

Якщо команда показує багато результатів, локальне видалення .vite усуває лише поточний симптом.

Тоді потрібно відновити нормальний ownership для всього дерева залежностей.

BASH - Повернути node_modules поточному користувачу
sudo chown -R \  "$(id -un)":"$(id -gn)" \  node_modules
Я змінюю ownership тільки там, де підтвердила проблему. Не потрібно робити recursive chown усього project directory без причини.

Інший чистий варіант - перевстановити dependencies правильним користувачем

Якщо ownership усього node_modules хаотичний або я не довіряю його поточному стану, інколи простіше створити залежності заново.

BASH - Чисто перевстановити dependencies
sudo rm -rf node_modules npm ci

sudo тут знову потрібен тільки для видалення root-owned дерева. Сам npm ci запускається вже від звичайного користувача.

Цей підхід доречний, коли в проєкті є актуальний package-lock.json.

Чому chmod 777 не є виправленням

Побачивши permission error, легко спробувати зробити каталог writable для всіх.

Це приховує причину, але не виправляє модель ownership.

BASH - Команда, якої я уникаю
# Do not use this as a fix:chmod -R 777 node_modules

Правильне питання не "як дозволити всім писати?", а "який користувач повинен володіти файлами і чому їх створив root?".

Чому sudo npm run dev тільки погіршує проблему

Запуск sudo npm run dev може тимчасово прибрати EACCES, тому що root має право змінити root-owned cache.

Але після цього нові файли Vite знову створюються від root.

Наступний запуск без sudo повертає ту саму проблему.

Чому sudo створює замкнене коло
Wrong recovery: EACCES  |  vsudo npm run dev  |  vmore root-owned files  |  vnormal npm run dev  |  vEACCES again
Не запускаю npm install, npm run dev або Vite від root тільки для того, щоб обійти filesystem permissions.

Docker ускладнює ownership через UID і GID

У Docker ім'я користувача всередині контейнера і на host може відрізнятися. Для bind mount важливими є UID і GID процесу, який реально створює файл.

Якщо container process має UID 0, файл на host може стати власністю root.

BASH - Порівняти користувачів host і container
id -uid -g docker compose exec workspace id

Назва service у конкретному Laradock setup може бути іншою, тому я перевіряю той service, у якому фактично запускаю Node.

У Laradock я хочу один стабільний ownership contract

Найкраще рішення - не виправляти permissions після кожного запуску, а зробити так, щоб процеси від початку створювали файли правильним користувачем.

Для bind-mounted project directory container user повинен бути узгоджений з host UID/GID або використовувати іншу чітко визначену модель.

  • Не запускати Node commands від root без необхідності.
  • Перевірити UID/GID користувача у Node-capable container.
  • Не змішувати root container і host user для одного node_modules.
  • Якщо Node запускається на host - послідовно використовувати host user.
  • Якщо Node запускається в container - послідовно використовувати налаштованого non-root user.
  • Після зміни Laradock configuration один раз очистити старі root-owned artifacts.

Multi-PHP setup не означає, що Node теж треба запускати різними способами

У мене локально кілька PHP runtime для різних проєктів, і це зручно вирішується окремими Laradock workspace та wrapper-командами.

Але Node filesystem ownership - інша задача.

Навіть якщо PHP 8.3, 8.4 і 8.5 живуть у різних services, файли frontend одного проєкту все одно повинні мати один зрозумілий ownership contract.

Про сам multi-PHP workflow я окремо писала у статті про PHP 8.3, 8.4 і 8.5 у Laradock з dphp, dartisan та dcomposer.

PHP upgrade і Node permissions можуть перетнутися випадково

Під час оновлення runtime легко виконати частину команд у container, частину на host, а окрему команду випадково запустити від root.

Після цього проблема проявляється вже пізніше, коли Vite намагається перегенерувати кеш.

У мене вже був окремий великий upgrade Laravel environment до PHP 8.5, який я описувала у матеріалі про PHP 8.5, Laravel, Laradock і Composer package upgrade. Такі зміни особливо добре показують, чому runtime users потрібно контролювати окремо від версій PHP.

Мій порядок виправлення EACCES

Перевірка

Дія

Root-owned тільки .vite

Видалити node_modules/.vite і запустити Vite без sudo

Root-owned багато файлів у node_modules

Виправити ownership або перевстановити dependencies

Root-owned весь project

Знайти процес, який створює файли від root, а не робити blind chmod

Проблема повертається після Docker

Перевірити UID/GID container process

Як я перевіряю, що проблема справді виправлена

BASH - Фінальна перевірка ownership і Vite
find node_modules \  -user root \  -print \  -quit npm run dev
  • Vite запускається без sudo.
  • node_modules/.vite створюється поточним користувачем.
  • Повторний запуск dev server не дає EACCES.
  • У node_modules не з'являються нові root-owned файли.
  • Docker або Laradock не повертає проблему після наступного запуску.
  • package.json і package-lock.json не довелося змінювати для permission fix.

Що я б не робила

  • Не запускала б sudo npm run dev.
  • Не запускала б sudo npm install як звичайний спосіб роботи.
  • Не використовувала б chmod -R 777 node_modules.
  • Не видаляла б весь node_modules, якщо проблема тільки у Vite cache.
  • Не робила б recursive chown усього project directory без перевірки.
  • Не змішувала б host Node і root container Node для одного dependency tree.
  • Не шукала б проблему в Laravel application code, поки filesystem уже показує root ownership.

EACCES у Vite часто виглядає як frontend problem, але насправді це простий конфлікт між користувачем, який створив кеш, і користувачем, який намагається його оновити.

Що я залишила собі на майбутнє

  • При EACCES спочатку перевіряти owner і permissions.
  • node_modules/.vite вважати generated cache, який можна перегенерувати.
  • Починати з найменшого можливого виправлення.
  • Використовувати sudo тільки для очищення вже неправильних root-owned artifacts, а не для запуску Node.
  • Не замінювати ownership проблему широкими permissions.
  • У Docker перевіряти UID/GID процесу, який пише в bind mount.
  • У Laradock зберігати один стабільний ownership contract для frontend files.
  • Після runtime upgrade перевіряти, від якого користувача виконувались Node commands.

Висновок

Помилка EACCES: permission denied, unlink у моєму випадку не вимагала змін у Laravel або Vite configuration.

Vite просто намагався оновити свій generated cache, але частина node_modules/.vite належала root.

У ICanUp правильним рішенням стало відновити ownership contract: видалити або виправити root-owned artifacts і надалі запускати Node одним узгодженим non-root користувачем.

Найважливіше тут не навчити Vite обходити permissions, а перестати створювати frontend files неправильним користувачем.