アルアカ - Arcadia Academia

Arcadia Academiaは「エンジニアリングを楽しむ」を合言葉に日本のデジタル競争力を高めることをミッションとするテックコミュニティです。

exec format error の直し方|Docker・npmでarm64とx64が混ざったときの実務対処【2026年版】

Featured image of the post

「MシリーズのMacでビルドしたイメージをサーバに持っていったら起動しない」「CIでは通るのに本番だけ落ちる」「node_modules をコピーしたら壊れた」——そしてログに出るのはたった一行、exec format error

このエラーは情報量が極端に少ないので慌いますが、原因はほぼ4つに限られます。本記事では3行のコマンドで原因を特定する手順と、ケース別の直し方、そしてよく混同される別のエラーとの見分け方までを整理します。

💡
30秒で要点

exec format error の正体は ENOEXEC。カーネルが「このファイルを実行形式として認識できない」と言っている
・実務では9割がCPUアーキテクチャの不一致(arm64 ↔ x86_64)
・切り分けは3行。uname -m で実行環境、file でバイナリ、docker image inspect でイメージのアーキを見る
・頑固な原因は node_modules や venv をアーキ違いのままコピーしていること。.dockerignore で防ぐ
・アーキと無関係な原因もある。shebangがないスクリプトを直接execveした場合
CRLFはこのエラーではないbad interpreter: No such file or directory になるので区別できる

💡
マルチアーキ環境のCI/CD設計や、Dockerビルドの最適化のご相談はお気軽にどうぞ!

ご環境に合わせた構成をご提案します。

お問合せはこちら


[目次を開く]

1. exec format error とは何か

このメッセージは、Linuxカーネルが返す ENOEXEC というエラー番号の表示です。意味はシンプルで、

「実行しようとしたファイルを、実行可能な形式として認識できなかった」

ということです。ファイルが存在しないわけでも、権限がないわけでもありません。ファイルはそこにあって実行権もあるのに、中身がカーネルの知っている形式ではない、という状態です。

Dockerでは次のような形で現れます。

exec /app/server: exec format error

古めのDockerだとこういう表示になることもあります。

standard_init_linux.go:228: exec user process caused: exec format error

2. まず3行で切り分ける

推測で直し始める前に、実行環境とバイナリのアーキテクチャを並べて見ます。これでほぼ決着します。

# ① 今動いている環境のアーキ
uname -m
# x86_64  → Intel/AMD 64bit
# aarch64 → ARM 64bit

# ② 問題のバイナリ/スクリプトの正体
file ./server
# ELF 64-bit LSB executable, x86-64 ...      → x64 用
# ELF 64-bit LSB executable, ARM aarch64 ... → arm64 用

# ③ Docker イメージのアーキ
docker image inspect myapp:latest --format '{{.Os}}/{{.Architecture}}'
# linux/amd64 または linux/arm64

①と②(もしくは③)が食い違っていたら、原因はアーキ不一致で確定です。

flowchart TB
    A["exec format error"] --> B{"file の出力は<br>ELF バイナリか"}
    B -->|"ELF だが<br>uname -m と違う"| C["アーキ不一致<br>ケース 1〜3"]
    B -->|"ASCII text など<br>スクリプト"| D["shebang 欠落<br>ケース 4"]
    C --> E{"どこで混ざったか"}
    E -->|"docker image inspect が違う"| F["ケース 1<br>イメージのアーキ違い"]
    E -->|"node_modules / venv をコピーした"| G["ケース 2<br>ネイティブモジュール"]
    E -->|"CI だけで発生"| H["ケース 3<br>runner のアーキ"]
💡
自分のPCのアーキテクチャがそもそもよくわからない場合は、OS別の確認方法をARM64とx64の違い・確認方法にまとめています。

3. ケース1:Dockerイメージのアーキ違い

最も多いパターンです。Apple SiliconのMac(arm64)でビルドしたイメージを、x64のサーバやEC2に持っていって起動しない、というやつです。

応急処置:実行時にプラットフォームを指定する

docker run --platform linux/amd64 myapp:latest

ただしこれはQEMUによるエミュレーションなので大幅に遅くなります。開発中の応急処置と割り切り、本番には使わないでください。

エミュレータが入っていないLinuxホストでは、先にbinfmtを入れる必要があります。

docker run --privileged --rm tonistiigi/binfmt --install all

根本対応:マルチアーキでビルドする

本番のアーキに合わせてビルドするのが正解です。buildx を使います。

# 両アーキ向けにビルドしてレジストリにpush
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myrepo/myapp:latest \
  --push .

こうしておけば、pullする側のアーキに合ったイメージが自動で選ばれます。x64サーバにしかデプロイしないのであれば、--platform linux/amd64 だけでビルドしても構いません。


4. ケース2:node_modules をアーキ違いで持ち込んだ

これが一番気づきにくいパターンです。イメージのアーキは正しいのに、中身のネイティブモジュールだけが違うアーキという状態です。

原因はほぼこれです。

# Dockerfile
COPY . .        # ← ホストの node_modules ごとコピーされている

Mac(arm64)で npm install してできた node_modules には、arm64用にビルドされたバイナリesbuildsharprollup、node-gyp経由の.nodeファイルなど)が入っています。これをx64のイメージに持ち込むと壊れます。

直し方

# ホスト側の残骸を消して入れ直す
rm -rf node_modules package-lock.json
npm install

# ネイティブモジュールだけ再ビルドするなら
npm rebuild

二度と起こさない:.dockerignore

根本対策はホストの node_modules をイメージに入れないことです。

# .dockerignore
node_modules
npm-debug.log
.venv
__pycache__
*.pyc
.git

コンテナ内で npm ci を走らせれば、そのアーキに合ったバイナリが入ります。

⚠️
Pythonでも同じことが起きます。 .venvsite-packages をそのままコピーすると、ビルド済みのwheel(.so)がアーキ違いで壊れます。numpyやPillowなどネイティブ拡張を持つパッケージで顕著です。こちらも .dockerignore で除外し、コンテナ内で pip install してください。

5. ケース3:CIとローカルでアーキが違う

「ローカルでは動くのにCIで落ちる」「CIでは通るのに本番で落ちる」ケースです。

GitHub Actionsでは、runnerのラベルでアーキが決まります

runner アーキテクチャ
ubuntu-latest / ubuntu-24.04 x86_64
ubuntu-24.04-arm arm64
macos-latest arm64(Apple Silicon)

なおarm64のホストrunnerは、パブリックリポジトリ向けが2025年8月にGA、プライベートリポジトリ向けも2026年1月に利用可能になっています。選択肢が増えた分、意図せず混在させてしまう事故も増えています

本番がx64なのにMacでしか確認していない、という状態を避けるには、CIで本番と同じアーキをビルドします。

# .github/workflows/build.yml
jobs:
  build:
    runs-on: ubuntu-latest      # x64
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - name: Build for production arch
        run: |
          docker buildx build --platform linux/amd64 -t myapp:ci --load .

6. ケース4:shebangがない(アーキは無関係)

ここが見落とされがちです。アーキテクチャが完全に一致していても exec format error は出ます

シェルスクリプトの1行目にshebang(#!/bin/bash など)がない場合、カーネルは「このファイルを何で実行すればいいのか」が判断できず、ENOEXECを返します。

# 1行目を確認する
head -1 entrypoint.sh

# なければ追加する
#!/bin/bash

Dockerで ENTRYPOINT ["/app/entrypoint.sh"] のようにexec形式で書いていると、シェルを介さずに直接execveされるため、この問題が顔を出します。

混同されやすい別のエラー:CRLF

「Windowsで編集したスクリプトが動かない」とき、改行コード(CRLF)を疑うのは正しいのですが、CRLFは exec format error にはなりません。ここを混同すると切り分けを間違えます。

原因 出るメッセージ
shebangがない exec format error(ENOEXEC)
アーキ不一致 exec format error(ENOEXEC)
改行がCRLF /bin/bash^M: bad interpreter: No such file or directory
shebangのパスが間違っている bad interpreter: No such file or directory

つまり bad interpreter と出ているならアーキを疑う必要はありません。CRLFならこう直します。

# 確認(CRLF なら \r\n と出る)
file entrypoint.sh

# 変換
dos2unix entrypoint.sh
# dos2unix がなければ
sed -i 's/\r$//' entrypoint.sh

7. 予防:混在を起こさない仕組み

一度直しても、仕組みがなけれまた同じことが起きます。最低限この3つを入れておくと安全です。

.dockerignore を必ず置く

ケース2の根絶です。リポジトリ作成時のテンプレートに入れてしまいましょう。

② Dockerfileでベースイメージのアーキを意識する

クロスビルドするなら、buildxが渡す変数を使えます。

FROM --platform=$BUILDPLATFORM node:22 AS builder
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "building on $BUILDPLATFORM for $TARGETPLATFORM"

③ CIで本番と同じアーキをビルドする

ローカルのMacでしか確認しない運用をやめ、CIを「本番アーキでの検証の場」にします。


まとめ

  • exec format error の正体は ENOEXEC。「ファイルを実行形式として認識できない」という意味で、ファイルの有無や権限の問題ではない
  • 切り分けは3行。uname -m / file / docker image inspect を並べて見ればほぼ決着する
  • ケース1(イメージのアーキ違い)は docker buildx build --platform で根本対応する。--platform での実行は遅いので応急処置に留める
  • ケース2(node_modules / .venv の持ち込み)が最も気づきにくい。.dockerignore で除外してコンテナ内で入れ直す
  • ケース4の shebang欠落はアーキと無関係head -1 で即座に確認できる
  • CRLFはこのエラーではなく bad interpreter になる。メッセージで見分けられる

エラーメッセージが短いだけで、原因の範囲は狭いエラーです。まず3行切り分けを回してから手を動かしてください。

💡
マルチアーキ環境のCI/CD設計やDockerビルドの最適化のご相談はお気軽にどうぞ!

お問合せはこちら

よくある質問(FAQ)

Q. --platform linux/amd64 を付ければ解決では?

動くようにはなりますが、QEMUによるエミュレーションなので大幅に遅くなります。ビルドに数倍の時間がかかることもあります。開発中に一時的に使うのは良いですが、本番はターゲットアーキでネイティブにビルドしてください。

Q. Apple SiliconのMacでx64イメージを快適に動かす方法は?

Docker Desktopには、x86エミュレーションにRosettaを使うオプションがあります。QEMU単体よりは速くなりますが、それでもネイティブには及びません。Rosettaの仕組みはRosetta 2とは?で解説しています。

Q. イメージは正しいのにまだ出ます

ケース2を疑ってください。 イメージ自体のアーキが合っていても、中の node_modules.venv が別アーキだと同じエラーになります。コンテナに入って file node_modules/**/*.nodefile .venv/**/*.so を見ると一発でわかります。

Q. qemu-user-statictonistiigi/binfmt はどちらを使う?

どちらもbinfmt_miscにエミュレータを登録するもので目的は同じです。Docker環境では tonistiigi/binfmt が手軽で、buildxのドキュメントでもこちらが案内されています。Docker Desktopを使っている場合は既定で有効なため、通常はどちらも不要です。

関連記事

📄Arrow icon of a page linkARM64とx64の違い・確認方法を解説|Windows/Mac/Linux対応【2026年版】

📄Arrow icon of a page linkRosetta 2とは?Apple SiliconでIntelアプリを動かす仕組みと終了時期|確認・有効化方法【2026年最新】

📄Arrow icon of a page linkDockerとは何か?その概要と利点を解説

📄Arrow icon of a page linkWSLが重い・メモリを食う問題を.wslconfigで直す完全ガイド【2026年版】


関連記事

開発環境の構築でお困りですか?

WSL、Docker、VSCodeなど、環境構築のつまずきを一緒に解決します。

  • 環境構築でエラーが解決できない
  • Dockerの使い方がわからない
  • 効率的な開発環境を整えたい
まずは30分の無料相談

相談は完全無料・オンラインで気軽に

あなたを爆速で成長させるメンタリングプログラムはこちら

メンタープログラムバナー

学習・開発のお悩みは現役エンジニアに相談

メンタープログラムの詳細を見る

エンジニアの基礎学習ゲーム

プログラミング学習支援

無料相談はこちら