マガジン

「自分のPCでは動くのに」を直す:環境差をAIと洗い出すチェック表

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

机の上の比較シートに、二つの実行環境の違いを鉛筆で記入する手元
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

本番(またはCI、友人のPC)で動かないとき、いちばん効率がよいのは、エラー文を読み込む前に「動く環境」と「動かない環境」を同じ項目で並べることです。差が見つかった項目が、原因の候補になります。AIにはこの比較表の作成と差分の読み取りを任せ、どれが本当の原因かは、人が1項目ずつ揃えて再実行して確かめます。 この記事では、AIが書いたプログラムを直したい人向けに、次の3つを用意しました。 • 両環境の情報を同じ形で書き出す比較シート • シートの情報を自動で集める小さなスクリプト(説明用の例) • 比較結果をAIに渡す依頼文と、差分の優先順位表 なお、スクリプトや依頼文は説明用の例で、この記事のために実行して結果を確かめたものではありません。自分の環境で試して、出力を確認してから使ってください。

この記事の目次
  1. まず比較シートを埋める
  2. 情報を集めるスクリプト(説明用の例)
  3. 項目ごとに、なぜ差が出るのか
  4. AIに渡す依頼文
  5. 差分の優先順位表
  6. 確かめるときの進め方

まず比較シートを埋める

次の表を、動く環境(A)と動かない環境(B)の両方で埋めます。AIに頼む場合も、この形を崩さずに渡すと差分を見つけてもらいやすくなります。

  • 実行環境、項目:OS・CPUの種類、環境A(動く):、環境B(動かない):、確認のしかた:スクリプトのplatform/arch
  • 実行環境、項目:Nodeのバージョン、環境A(動く):、環境B(動かない):、確認のしかた:node -v
  • 実行環境、項目:npmのバージョン、環境A(動く):、環境B(動かない):、確認のしかた:npm -v
  • 依存関係、項目:ロックファイルの有無、環境A(動く):、環境B(動かない):、確認のしかた:スクリプトのlockfile
  • 依存関係、項目:インストール方法、環境A(動く):、環境B(動かない):、確認のしかた:実行したコマンドをそのまま書く
  • 設定、項目:環境変数(名前と有無のみ)、環境A(動く):、環境B(動かない):、確認のしかた:スクリプトのenv
  • 設定、項目:NODE_OPTIONSの有無、環境A(動く):、環境B(動かない):、確認のしかた:環境変数の一覧で確認
  • ファイル、項目:作業ディレクトリ、環境A(動く):、環境B(動かない):、確認のしかた:cwd
  • ファイル、項目:パス区切り・大文字小文字、環境A(動く):、環境B(動かない):、確認のしかた:pathSep、ファイル名の綴り
  • ファイル、項目:改行コード設定、環境A(動く):、環境B(動かない):、確認のしかた:git config core.autocrlf、.gitattributes
  • 実行方法、項目:起動コマンド、環境A(動く):、環境B(動かない):、確認のしかた:package.jsonのscriptsなど

ポイントは、環境変数は値ではなく「設定あり/未設定/空文字」で書くことです。APIキーやDBの接続文字列をそのままAIのチャット欄に貼るのは避けます。

情報を集めるスクリプト(説明用の例)

両環境のプロジェクトのルートで実行し、出力をシートに写します。環境変数の値は出さず、有無と文字数だけを表示します。keysは自分のプロジェクトで使っている名前に書き換えてください。

js
// env-report.mjs  (説明用の例)
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';

const keys = ['NODE_ENV', 'NODE_OPTIONS', 'DATABASE_URL', 'API_KEY', 'PORT', 'TZ'];

const describe = (v) =>
  v === undefined ? '未設定' : v === '' ? '空文字' : `設定あり(${v.length}文字)`;

const report = {
  node: process.version,
  platform: process.platform,
  arch: process.arch,
  cwd: process.cwd(),
  pathSep: path.sep,
  ci: process.env.CI ?? '未設定',
  lockfile: ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock']
    .filter((f) => fs.existsSync(f)),
  env: Object.fromEntries(keys.map((k) => [k, describe(process.env[k])])),
};

console.log(JSON.stringify(report, null, 2));

実行はnode env-report.mjsです。Nodeのprocessには、process.version、process.platform、process.cwd()、process.envが用意されています。platformはlinux、darwin、win32などの文字列で返ります。

項目ごとに、なぜ差が出るのか

OSとパス

Nodeのpathモジュールの説明では、パス区切り(path.sep)はWindowsが\、POSIX系が/です。PATHのような環境変数の区切り文字(path.delimiter)はWindowsが;、POSIX系が:です。AIが書いたコードに'data\\file.txt'のような文字列の直書きやsplit('/')があると、OSが変わった時点で壊れます。

ファイル名の大文字小文字も要注意です。Logo.pngをlogo.pngと書いてしまっても、大文字小文字を区別しない設定の環境では動き、区別する環境では「ファイルが見つからない」になることがあります(編集上の経験則であり、環境の設定によります)。

環境変数

環境変数はプロセスごとに引き継がれるため、ターミナルで設定した値や.envの内容が、本番のサーバーやCIには存在しないことがよくあります。NodeのCLIドキュメントによると、NODE_OPTIONSでもNode.jsのオプションを渡せ、コマンドラインで直接指定した値のほうが優先されます。起動方法が違うと挙動が変わる原因になります。

またprocess.envに代入した値は文字列になる、とNodeのprocessの説明にあります。PORTやDEBUG=falseを数値や真偽値のつもりで比較しているコードは、設定の渡し方で結果が変わります。Windowsでは環境変数名の大文字小文字が区別されない点も、同じページに書かれています。

CIでは、GitHub Actionsの変数のドキュメントのとおりCIとGITHUB_ACTIONSがtrueになり、RUNNER_OSやRUNNER_ARCHなどのランナー情報も設定されます。コードがCIの有無で挙動を変えていないかも見る価値があります。

改行コード

Gitは設定によって、チェックアウト時に改行を変換できます。gitattributesではtextやeol属性、core.autocrlfの扱いが説明されています。シェルスクリプトがCRLFで保存されたためLinuxで失敗する、といった症状は、このあたりを疑います。リポジトリに.gitattributesがあるか、*.sh text eol=lfのように指定されているかを比べてください。

Nodeのバージョン

Nodeにはリリース区分があり、本番アプリケーションにはActive LTSかMaintenance LTSを使うことが案内されています。手元がCurrent版で本番がLTSの場合は、バージョン差を確認する候補になります。バージョンの差が出たら、手元のほうを本番に合わせるのが最初の手です。

AIに渡す依頼文

シートとスクリプトの出力を貼り、次のように頼みます。エラー文があれば、機密部分を伏せて一緒に渡します。

手元(環境A)では動き、本番(環境B)では動かないプログラムの原因を探しています。
下の2つの環境情報を比べて、次の順に答えてください。

1. 差がある項目の一覧(表形式)
2. 各差がエラー内容に関係しそうな理由と、可能性の高さ(高/中/低)
3. 1項目ずつ確かめるための手順(1回に変える項目は1つ)
4. 追加で教えてほしい情報

守ってほしいこと:
- 情報が足りない項目は推測で埋めず「不明」と書く
- 原因を断定せず、確認方法とセットで書く
- 環境変数の値は伏せてあるので、値の中身は想像しない

【エラーメッセージ(伏せ字済み)】
(ここに貼る)

【環境A(動く)】
(スクリプトの出力)

【環境B(動かない)】
(スクリプトの出力)

コードの修正案が欲しい場合は、先に原因の候補を確認してから「パス区切りの直書きをなくす修正案」のように範囲を決めて頼むほうが安全です。

差分の優先順位表

AIが返した差分は、次の表で確認の順番を決めます。これは編集上の目安です。

  • Nodeのバージョン、エラーの出方の例:構文エラー、未対応のAPI、先に確かめること:Bのバージョンに揃えてAで再実行
  • 環境変数が未設定、エラーの出方の例:undefinedの参照、接続失敗、先に確かめること:Bに名前が登録されているか、空文字ではないか
  • OS・パス、エラーの出方の例:ファイルが見つからない、先に確かめること:パスをpath.joinなどで組み立てているか
  • 改行コード、エラーの出方の例:シェルが起動しない、diffが全行に出る、先に確かめること:.gitattributesとcore.autocrlf
  • ロックファイルなし、エラーの出方の例:依存パッケージの版が違う、先に確かめること:ロックファイルをコミットして同じ版を入れる

確かめるときの進め方

  1. 差分のうち、1つだけを環境Aで本番に揃えます(例:Nodeのバージョンを合わせる)。
  2. 再現するか確かめます。再現したら、その差が原因の有力候補です。
  3. 再現しなければ元に戻し、次の項目へ進みます。複数を同時に変えると、何が効いたのか分からなくなります。
  4. 直ったら、原因になった項目をREADMEやCIの設定に書き残します。

AIは差分の整理と手順の提案には向いていますが、実際に環境を揃えて動かした結果は、人が確かめるものです。結果が想定と違った場合は、その出力をシートに追記して、もう一度同じ依頼文で渡してください。

出典・参考資料