MeWrite Docs

EACCES: permission denied

ファイルやディレクトリへのアクセス権限がない場合に発生するエラー

概要

EACCES: permission denied は、ファイルやディレクトリへのアクセス権限がない場合に発生するエラーです。npm グローバルインストールや、ファイル操作時によく発生します。

エラーメッセージ

Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/package'
Error: EACCES: permission denied, open '/var/log/app.log'

原因

  1. npm グローバルディレクトリの権限: root 権限が必要なディレクトリにインストール
  2. ファイルの所有者: 別のユーザーが所有するファイル
  3. ディレクトリの権限: 書き込み権限がないディレクトリ
  4. ポートの使用: 1024 以下のポートは root 権限が必要

解決策

1. npm グローバルディレクトリの変更(推奨)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# npm のグローバルディレクトリを変更
mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'

# PATH に追加(~/.bashrc または ~/.zshrc)
export PATH=~/.npm-global/bin:$PATH

# 設定を反映
source ~/.bashrc  # または source ~/.zshrc

# グローバルインストールを試す
npm install -g package-name

2. nvm を使用(推奨)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# nvm のインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

# シェルを再起動または
source ~/.bashrc

# Node.js のインストール
nvm install --lts
nvm use --lts

# グローバルインストール(sudo 不要)
npm install -g package-name

3. 既存ディレクトリの所有者を変更

1
2
3
4
5
6
7
# npm ディレクトリの所有者を変更
sudo chown -R $(whoami) /usr/local/lib/node_modules
sudo chown -R $(whoami) /usr/local/bin
sudo chown -R $(whoami) /usr/local/share

# npm キャッシュの所有者を変更
sudo chown -R $(whoami) ~/.npm

4. ファイル・ディレクトリの権限を変更

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 読み取り権限を追加
chmod +r filename

# 書き込み権限を追加
chmod +w filename

# 実行権限を追加
chmod +x filename

# 再帰的に権限を変更
chmod -R 755 directory

# 所有者を変更
sudo chown $(whoami) filename
sudo chown -R $(whoami) directory

5. プロジェクトローカルのインストール

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# グローバルインストールを避ける
# ❌ 権限の問題が発生しやすい
sudo npm install -g package-name

# ✅ ローカルインストール + npx
npm install package-name
npx package-name

# ✅ package.json の scripts に追加
# package.json
{
    "scripts": {
        "lint": "eslint .",
        "test": "jest"
    }
}
npm run lint

6. ポートの権限問題

1
2
3
4
5
6
7
8
// ❌ 1024 以下のポートは root が必要
const server = app.listen(80);

// ✅ 1024 以上のポートを使用
const server = app.listen(3000);

// ✅ リバースプロキシを使用(Nginx)
// Nginx が 80 番で受けて、3000 番に転送
1
2
3
# どうしても 80 番を使いたい場合
# Linux で setcap を使用
sudo setcap 'cap_net_bind_service=+ep' $(which node)

7. Docker での権限問題

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# ❌ root ユーザーで実行
FROM node:18
WORKDIR /app
COPY . .
RUN npm install

# ✅ 非 root ユーザーで実行
FROM node:18
WORKDIR /app
COPY --chown=node:node . .
USER node
RUN npm install

8. CI/CD での対処

1
2
3
4
5
6
7
8
9
# GitHub Actions
- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '18'

# npm キャッシュの権限問題を回避
- name: Install dependencies
  run: npm ci

Node.js コードでの対処

ファイル存在・権限確認

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const fs = require('fs');

// 権限を確認
fs.access('/path/to/file', fs.constants.R_OK | fs.constants.W_OK, (err) => {
    if (err) {
        console.error('No read/write access');
    } else {
        console.log('Can read/write');
    }
});

// Promise 版
const { access, constants } = require('fs/promises');

async function checkAccess(path) {
    try {
        await access(path, constants.R_OK | constants.W_OK);
        return true;
    } catch {
        return false;
    }
}

エラーハンドリング

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const fs = require('fs/promises');

async function writeFile(path, content) {
    try {
        await fs.writeFile(path, content);
    } catch (err) {
        if (err.code === 'EACCES') {
            console.error(`Permission denied: ${path}`);
            // 代替パスに書き込むなどの対処
        }
        throw err;
    }
}

デバッグのコツ

権限の確認

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ファイルの権限を確認
ls -la /path/to/file

# ディレクトリの権限を確認
ls -la /path/to/directory

# 現在のユーザーを確認
whoami

# ファイルの所有者を確認
stat /path/to/file

npm の設定確認

1
2
3
4
5
6
7
8
# npm の設定を表示
npm config list

# グローバルディレクトリを確認
npm config get prefix

# キャッシュディレクトリを確認
npm config get cache

Node.js の他のエラー

最終更新: 2025-12-08