LINE予約「LUCA」の機能と料金はこちら

n8nのCodeノードで「fetch is not defined」が出る原因と直し方

n8n 実務ノート 公開

n8n の Code ノードに await fetch(url) と書くと、実行した瞬間に「fetch is not defined」で止まります。弊社でも n8n をアップグレードした直後にこのエラーが本番で出続け、しばらく気づけませんでした。この記事では n8n 本体のソースで原因を確かめ、this.helpers.httpRequest へ書き換える手順をまとめます。

この記事の結論

  • n8n 2.19.2 の Code ノードは、JavaScript を「タスクランナー」という別の実行環境に渡して動かします。既定の設定では、そこに用意されている名前の一覧に fetch が入っていないため、呼ぶと ReferenceError になります。
  • 直し方は this.helpers.httpRequest({ method, url, headers, body, json: true }) への書き換えです。戻り値は応答の本文そのもので、200 以上 300 未満でない応答は例外として投げられます。
  • body はオブジェクトのまま渡します。JSON 文字列にするのは axios の役目なので、自分で JSON.stringify する必要はありません。
  • HTML を組み立てる Code ノードでは、fetch( がテンプレート文字列の中か外かを見ます。中ならブラウザで動くので書き換えず、外なら n8n 側で動くので書き換えます。

実際に起きたこと

弊社は 2026-05-06 に n8n を 2.4.6 から 2.19.2 へ上げました。その直後から、Code ノードの中で fetch() を使っていたワークフローが「ReferenceError: fetch is not defined at VmCodeWrapper」で止まるようになりました。

実害が出たのは、検索の計測データを LINE へ日次で届けるワークフローの中の Code ノード2つ、日次レポートと緊急アラートです。エラーは7日連続で続き、2026-05-13 に直しました。止めてあった別のワークフローにも同じ書き方が残っていて、そちらは再び有効にした瞬間に同じエラーで落ちる状態でした。

直す途中で、もうひとつ落とし穴を踏みました。fetch( を機械的に検索すると、HTML を返す Code ノードのテンプレートに書かれたブラウザ側の fetch( まで26箇所引っかかったのです。こちらはブラウザで実行されるので直す必要がないのに、確かめずに「26箇所直す」と数えて後で訂正しました。

原因

Code ノードの JavaScript はタスクランナーで動く

n8n 2.19.2 の Code ノードの実体 Code.node.js は、言語が JavaScript のとき JsTaskRunnerSandbox を作り、startJob(‘javascript’, …) でコードを渡します。受け取って実行する側がタスクランナーです。

公式ドキュメントも、タスクランナーが Code ノードの JavaScript と Python を実行すると説明しています。有効化の設定 N8N_RUNNERS_ENABLED は n8n 2.0 から非推奨で、設定しなくてもこの経路で動きます。

タスクランナーは node:vm の新しいコンテキストでコードを走らせる

タスクランナーの js-task-runner.js は、Node.js 標準の node:vm を読み込み、createContext で新しいコンテキストを作り、その中で runInContext によりコードを実行します。Node.js のドキュメントによると、createContext に渡したオブジェクトがそのコンテキストのグローバルになり、そこにあるのは渡したオブジェクトの持ち物と、標準のグローバルオブジェクトが持つ組み込みの関数です。

それ以外のグローバルは、渡さなければ入りません。buildContext が渡しているのは、require、console、$getWorkflowStaticData、$json などのデータプロキシ、this.helpers 経由の関数、そして getNativeVariables が返す次の名前です。

Buffer
setTimeout, setInterval, setImmediate
clearTimeout, clearInterval, clearImmediate
btoa, atob
TextDecoder, TextDecoderStream
TextEncoder, TextEncoderStream
FormData

この一覧に fetch はありません。Node.js 本体にある fetch が、Code ノードのコードが動くコンテキストには持ち込まれていない。これが原因です。

なお、これは既定の設定の話です。N8N_RUNNERS_INSECURE_MODE を true にすると runDirectly という別の経路になり、new Function と with(context) でランナーのプロセスの中で直接動きます。この記事では既定の経路だけを扱います。

エラー文の形

ユーザーのコードは、VmCodeWrapper という名前の async 関数で包んでから実行されます。

module.exports = async function VmCodeWrapper() {<Code ノードの中身>
}()

スタックトレースに「at VmCodeWrapper」が出るのはこのためです。画面の文言は execution-error.js が組み立てます。「ReferenceError: fetch is not defined」の行を「:」で分け、後ろ側を本文に、前側の「ReferenceError」を説明に入れ、本文の末尾に [line 行番号] を付けます。

公式ドキュメントの立場

Code ノードの公式ドキュメントには「You can’t access the file system or make HTTP requests. Use the following nodes instead:」とあり、HTTP Request ノードを勧めています。一方でソースの runner-types.js には、タスクランナーからメインプロセスへ呼び出せる関数の一覧 EXPOSED_RPC_METHODS があり、helpers.httpRequest が載っています。呼び出しはメインプロセスへ送られ、そこで実際の HTTP 通信が行われます。弊社の本番もこの経路で動いています。

直し方

残っている fetch( を探す

まず、Code ノードに fetch( が残っていないかを調べます。弊社の点検では次の正規表現で検出しています。前にドットや英数字が付かない fetch( だけを拾う形です。

(?<![\w.])fetch\s*\(

ワークフローの中身は API で取り出せます。取り出した JSON を、同じ正規表現で数えます。弊社の点検が Python なので、ここも Python です。

curl -s -H "X-N8N-API-KEY: XXXX" \
  http://localhost:5678/api/v1/workflows/<ワークフローID> \
  -o wf.json
python3 -c "import re; print(len(re.findall(r'(?<![\w.])fetch\s*\(', open('wf.json').read())))"

注意が要るのが、HTML を返す Code ノードです。jsCode に <!DOCTYPE や <html、document.、location.、alert( といった語があれば、HTML を組み立てているノードの可能性が高いです。ただし、それだけでは拾った fetch( がブラウザ側のものとは決まりません。HTML を返すノードでも、返す前に n8n 側で await fetch() を呼ぶ形はあり得ます。fetch( がテンプレート文字列の中か外かを一つずつ見ます。中ならブラウザで動くので書き換えず、外なら n8n 側で動くので書き換えます。弊社が26箇所を「直す」と数えたのは、ここを見なかったからです。

this.helpers.httpRequest に書き換える

書き換え前です。

const res = await fetch(url, {
  method: 'POST',
  headers,
  body: JSON.stringify(data),
});
return [{ json: { sent: res.ok, status: res.status } }];

書き換え後です。

let sent = false;
let message = '';
try {
  await this.helpers.httpRequest({
    method: 'POST',
    url,
    headers,
    body: data,   // オブジェクトのまま渡す
    json: true,
  });
  sent = true;
} catch (e) {
  message = e && e.message ? String(e.message) : String(e);
}
return [{ json: { sent, message } }];

変わった点です。

  • URL は第一引数ではなく url という項目で渡し、method、headers、body、json も同じオブジェクトに入れます。項目名は n8n-workflow の型定義 IHttpRequestOptions にあります。
  • body はオブジェクトのまま渡します。ソースの convertN8nRequestToAxios を読むと、body はそのまま axios の data に入り、json: true がやることは Accept ヘッダを application/json にすることだけです。data がオブジェクトなら、Content-Type を application/json にして JSON 文字列にするのは axios の役目です。自分で JSON.stringify した文字列を渡すと axios はオブジェクトとして扱わず、Content-Type を自分で付けていなければ application/json も付きません。弊社の点検では、この組み合わせを警告として拾っています。
  • 戻り値は応答の本文です。fetch の res.ok や res.status に当たるものは返ってきません。

200 番台以外の応答を扱う

fetch はエラー応答でも例外を投げず、res.ok で判定させます。n8n-core の httpRequest は axios をそのまま呼び、axios の既定の validateStatus は status >= 200 && status < 300 です。それ以外の応答は例外として投げられ、Code ノードの catch に入ります。だから上の書き換えでは try/catch で sent を決めています。

ステータスコードを見たいときは returnFullResponse: true を付けると、戻り値が body、headers、statusCode、statusMessage を持つオブジェクトになります。例外にしたくないときは ignoreHttpStatusErrors: true を付けると、validateStatus が常に true になります。この項目は型定義とソースで確かめただけで、弊社の本番は try/catch の形です。

API で更新したときの反映

弊社の点検では、API で PUT しただけの状態を「DBは新版/実行は旧版」と呼び、PUT の後に deactivate と activate をやり直すことにしています。2.19.2 のソースでは、公開 API の PUT は publishIfActive: true で WorkflowService の update を呼び、nodes か connections が変われば新しい versionId を振り、有効なワークフローなら activateWorkflow でいったん外して登録し直します。つまり PUT だけで新しい版に切り替わる作りです。手順としては勧めず、弊社の運用として記しておきます。

直ったかを確かめる

  • 編集画面でその Code ノードだけを実行し、出力の sent が true で返ることを見ます。
  • API で取り出した JSON をもう一度数え、n8n 側で実行される fetch( が残っていないことを確かめます。テンプレートの中の分は残っていて構いません。
  • スケジュールで動くワークフローなら、次の実行が成功で終わるところまで見届けます。

それでも直らないとき

どの fetch かが分からない

エラー文の末尾の [line 行番号] で場所を絞れます。行番号はスタックトレースのうち、まず VmCodeWrapper を含まない evalmachine の行、無ければ VmCodeWrapper を含む evalmachine の行から取られます。この記事の例のようにトップレベルで await fetch() している場合は後者です。

helpers.httpRequestWithAuthentication を使っている

認証つきの helpers.httpRequestWithAuthentication は、タスクランナーの UNSUPPORTED_HELPER_FUNCTIONS の一覧に入っています。呼ぶと「The function “helpers.httpRequestWithAuthentication” is not supported in the Code Node」という例外になります。弊社は Authorization ヘッダを自分で組み、トークンは環境変数から $env で読んでいます。その $env が「access to env vars denied」で読めないときの直し方は、n8nのCodeノードで「access to env vars denied」が出る原因と直し方 にまとめています。

気づくのが遅れる

このエラーは実行のたびに出ますが、通知がなければ気づけません。弊社は7日間見逃しました。ワークフローの settings.errorWorkflow にエラー通知用のワークフローを設定しておくと、落ちた時点で知らせが届きます。弊社の点検では、有効なワークフローでこれが未設定なら最も重い指摘です。

まとめ

  • n8n 2.19.2 の Code ノードは、既定の設定では node:vm の新しいコンテキストでコードを動かし、fetch はそこに渡されていません。
  • HTTP 通信は this.helpers.httpRequest で行います。url は項目で渡し、body はオブジェクトのまま、json: true を付けます。
  • 戻り値は本文だけで、200 番台以外は例外になります。fetch の res.ok に頼っていた判定は try/catch に書き換えます。
  • HTML を返すノードでは、fetch( がテンプレート文字列の中か外かを見ます。中なら書き換えず、外なら書き換えます。
  • 直したら次の実行が成功するまで見届け、errorWorkflow で落ちたときの通知を用意します。

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

n8nの点検と構築のご相談

「Codeノードで fetch is not defined が出る」といったn8nの不具合の点検や、業務の自動化の仕組みづくりをお引き受けしています。

お問い合わせはこちら

この記事を書いた人

貫名 孝夫(マルタマーケティング株式会社 代表取締役)。n8nで140本を超えるワークフローを本番で動かしながら、実際に起きた不具合と直し方を記録しています。会社概要