Pythonで FileNotFoundError が出る原因とパス確認方法(Mac)


FileNotFoundError: [Errno 2] No such file or directory: 'data/items.csv' のように、ファイルはあるのに見つからないと言われる。原因の多くは、相対パスが「スクリプトの場所」ではなく「実行したときのカレントディレクトリ」から数えられていることです。

いちばん短い直し方は、スクリプト自身の場所を基準にパスを組み立てることです。

from pathlib import Path

BASE = Path(__file__).resolve().parent
target = BASE / "data" / "items.csv"

以下は、このサイトの運営に使っているMac(macOS 26.6.2)で、2026年10月19日に一時フォルダで再現した結果です。python3 はこのMacではAnacondaの 3.9.7 です。

再現:同じスクリプトが、実行する場所で成功したり失敗したりする

次の配置で、data/items.csv を相対パスで開くスクリプトを用意しました。

itm140/
└── myapp/
    ├── read_rel.py
    └── data/
        └── items.csv
import os
print("cwd:", os.getcwd())
with open("data/items.csv", encoding="utf-8") as f:
    print(f.readline().strip())

myapp の中で実行すると成功し、1つ上の itm140 から実行すると失敗しました。

$ cd itm140/myapp
$ python3 read_rel.py
cwd: /private/tmp/itm140/myapp
name,price

$ cd ..
$ python3 myapp/read_rel.py
cwd: /private/tmp/itm140
Traceback (most recent call last):
  File "/private/tmp/itm140/myapp/read_rel.py", line 3, in <module>
    with open("data/items.csv", encoding="utf-8") as f:
FileNotFoundError: [Errno 2] No such file or directory: 'data/items.csv'

エラーの読み方

  • 最後の行の 'data/items.csv' は、Pythonが実際に開こうとした文字列です。先頭が / でなければ相対パスで、カレントディレクトリ(cwd: の行)につなげて探されます。
  • 2つ目の実行では /private/tmp/itm140 + data/items.csv を探したことになり、そこには無いので失敗しました。
  • Tracebackの File "..." に出るのはスクリプトの場所で、ファイルを探した場所ではありません。ここを見て「同じフォルダにあるのに」と思うと迷います。

どこを探したかは、Path.resolve() で絶対パスにすると一目で分かります。同じ1行を2か所で実行しました。

$ python3 -c "from pathlib import Path; p=Path('data/items.csv'); print(p.resolve()); print(p.exists())"
(itm140 で実行)
/private/tmp/itm140/data/items.csv
False
(itm140/myapp で実行)
/private/tmp/itm140/myapp/data/items.csv
True

VS Codeの実行ボタンで起きやすい理由

VS Codeの設定 python.terminal.executeInFileDir は既定で false です。公式の設定リファレンスによると、これは「ファイルのあるフォルダではなく、現在のフォルダで実行する」という意味です。つまり、開いているワークスペースの直下がカレントディレクトリになりやすく、スクリプトをサブフォルダに置いていると上の2つ目と同じ状況になります。実行するPython自体が違う問題はVS Codeで選択されているPythonが違うときの確認・変更方法で扱っています。

直し方:__file__ を基準にする

from pathlib import Path
BASE = Path(__file__).resolve().parent
target = BASE / "data" / "items.csv"
print("__file__:", __file__)
print("target  :", target)
print(target.read_text(encoding="utf-8").splitlines()[0])

これを3つの場所から実行しました。target は毎回同じになり、すべて成功しました。

--- from /tmp/itm140
__file__: /private/tmp/itm140/myapp/read_file.py
target  : /private/tmp/itm140/myapp/data/items.csv
name,price
--- from myapp
__file__: /private/tmp/itm140/myapp/read_file.py
target  : /private/tmp/itm140/myapp/data/items.csv
name,price
--- from ~
__file__: /tmp/itm140/myapp/read_file.py
target  : /private/tmp/itm140/myapp/data/items.csv
name,price

3つ目だけ __file__ が /tmp/... になっています。ホームから python3 /tmp/itm140/myapp/read_file.py と打ったので、打ったとおりのパスが入りました。Macの /tmp は /private/tmp へのシンボリックリンク(ls -ld /tmp で /tmp -> private/tmp)なので、resolve() を通すと /private/tmp にそろいます。パスを文字列で比べる処理があるなら、resolve() してから比べるほうが安全です。

Macで見落としやすいもの

open() は ~ を展開しない

ターミナルでは ~ がホームに置き換わりますが、それはシェルの機能です。Pythonの open() に渡すと、~ という名前のフォルダを探してしまいます。

$ python3 -c "open('~/itm140_tmp_test/memo.txt')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '~/itm140_tmp_test/memo.txt'

同じファイルが、os.path.expanduser() か Path.expanduser() を通すと開けました。

import os
from pathlib import Path
open(os.path.expanduser("~/itm140_tmp_test/memo.txt"))
Path("~/itm140_tmp_test/memo.txt").expanduser().read_text()

スペース・全角スペース・濁点

日本語やスペースを含む名前を試しました。半角スペース入りの「売上 データ.csv」と、濁点を分解した形(NFD)で作った「ダウンロード.csv」の2つを置き、名前の書き方を変えて exists() と os.listdir() の結果を比べています。

listdir : ['ダウンロード.csv', '売上 データ.csv']
'売上 データ.csv' exists: True | in listdir: True
'売上 データ.csv' exists: False | in listdir: False
'売上データ.csv' exists: False | in listdir: False
'ダウンロード.csv' exists: True | in listdir: False
NFC len: 10 NFD len: 12
  • 「売上 データ.csv」(全角スペース)と「売上データ.csv」(スペースなし)は、見た目が近くても別の名前なので見つかりません。名前は手で打たず、os.listdir() の結果からコピーするのが確実です。
  • 「ダウンロード.csv」の行は、開く(exists())のは成功するのに、listdir() の一覧と文字列で比べると一致しません。このMacのAPFSでは、濁点が合成された形でも分解された形でも同じファイルとして開けました。一方で listdir() は作ったときの形(分解形、12文字)のまま返すので、in や == での比較だけが外れます。比べるときは unicodedata.normalize("NFC", 名前) でそろえます。

ターミナルで引数に渡すときは、スペースで2つに分かれる点にも注意します。

$ cat names/売上 データ.csv
cat: names/売上: No such file or directory
cat: データ.csv: No such file or directory
$ cat "names/売上 データ.csv"
a

書き込みでも出る:フォルダが無い

書き込みモードの open() はファイルは作りますが、途中のフォルダは作りません。out フォルダが無い状態で試すと、読み込みと同じ FileNotFoundError になりました。

$ python3 -c "open('out/result.txt', 'w')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'out/result.txt'
from pathlib import Path
p = Path("out/result.txt")
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text("ok")

ファイルもフォルダもあるのに開けない場合は、別のエラー(PermissionError)になります。そちらはPermissionError: [Errno 13] が出る具体例と回避策に、スクリプトを ./ で実行して permission denied になる場合はzsh: permission denied が出る原因まとめにまとめています。

参考にした公式ドキュメント

検証した環境

この記事の調査・再現・執筆は、運営者の指示のもとでAIエージェント(AnthropicのClaude)が行い、公開するかどうかは運営者が決めています。載せた出力は、そのAIエージェントがこのMacで実際にコマンドを実行して得たものです。

  • macOS 26.6.2(Apple Silicon)、起動ディスクは APFS
  • Python 3.9.7(Anaconda、このMacのPATH上の python3)
  • 再現は一時フォルダで実施(2026年10月19日)。~ の確認用に作ったホーム直下のフォルダは確認後に削除

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

トップへ戻る