◉RORK LABEN
●EXPO — EAS Observe がネイティブクラッシュも記録(10/07)。SDK 57 は 57.0.21 以降で確認できます●RORK — 09-29 に GPT-6.1 Sol、09-28 に Claude Sonnet 5.5 を追加。モデル選択で使えます●RN 0.88 — React Native 0.88.x の正式リリース予定は 10/12、残り2日●Q&A — AuthSession が Android の standalone で結果を返さない、という問いが長く続いています●WINDOWS — Mac がなくても Windows だけで iPhone アプリを出す手順が共有されています●NEW — Expo Go で通知だけが届かない夜に、先に切り分ける3点●EXPO — EAS Observe がネイティブクラッシュも記録(10/07)。SDK 57 は 57.0.21 以降で確認できます●RORK — 09-29 に GPT-6.1 Sol、09-28 に Claude Sonnet 5.5 を追加。モデル選択で使えます●RN 0.88 — React Native 0.88.x の正式リリース予定は 10/12、残り2日●Q&A — AuthSession が Android の standalone で結果を返さない、という問いが長く続いています●WINDOWS — Mac がなくても Windows だけで iPhone アプリを出す手順が共有されています●NEW — Expo Go で通知だけが届かない夜に、先に切り分ける3点
記事一覧/開発ツール
⬡ 開発ツール/2026-09-21中級

exit code 0 で止まるビルド — ログを黙らせていた設定と、空ファイルを通した存在チェック

eas build --local が exit code 0 but produced no further output で止まる件と、0 バイトのスタブが埋め込まれず dyld で落ちる件。どちらも原因は出力を減らす設定でした。自分のスクリプトを棚卸しする手順まで書き残します。

Rork577Expo213EAS Build20xcodebuildトラブルシューティング81iOS114

Rork で作ったアプリを GitHub へ書き出して、手元の Mac でビルドに移った方が最初に出会う種類の失敗があります。ターミナルに流れた最後の行が、これだけというものです。

error: the following command failed with exit code 0 but produced no further output

失敗コードが 0 という一行を前にして、私はしばらく画面を眺めておりました。0 は慣例として成功を指します。その 0 が error という語と並んでいるのですから、どちらを信じればよいのか分からなくなります。

同じ週に、もう一つ似た報告が並んでいました。ビルド自体は通るのに、実機に入れて起動した瞬間に落ちる、というものです。どちらも原因はコードの中ではなく、ビルドを進めるための小さな設定の側にありました。

exit code 0 は「成功」ではなく「何も言えませんでした」の印です

ひとつめは、Expo SDK 57 / React Native 0.86 という安定版の構成で、Xcode 27 のもとで eas build --platform ios --local を走らせたときの報告です。expo-modules-jsi の xcframework を組み立てる段で、先ほどの一行だけを残して止まります(expo/expo#50311)。

報告者が突き止めた原因は、その段で呼ばれる xcodebuild に -quiet が渡されていたことでした。-quiet は警告と進捗を抑えるための指定ですが、抑える対象に実際のエラー出力まで含まれてしまいます。外側の仕組みから見ると、子プロセスは何も言わずに終わったように見えます。だから「コマンドは失敗したが、それ以上の出力は生まれなかった」という、あの奇妙な文面になるのです。

-quiet を外して回し直すと、握りつぶされていた行がそのまま出てきて、修正後は App Store Connect への提出まで通ったと書かれています。

読者の皆さまに最初にお伝えしたいのは、この一行が出たときに疑う順番です。コードを疑う前に、その段で出力を減らしている設定があるかどうかを先に見ます。順番を逆にすると、存在しないバグを半日探すことになります。

手元で確かめるときは、静かなままログだけを残す形にしておくと後が楽になります。

# 失敗の再現時だけ -quiet を外し、出力は捨てずにファイルへ逃がす
# tee を挟むので画面にも流れ、あとから grep もできます
set -o pipefail   # xcodebuild の終了コードを tee で握りつぶさないための一行です
 
xcodebuild \
  -project ios/YourApp.xcodeproj \
  -scheme YourApp \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  build 2>&1 | tee "build-$(date +%Y%m%d-%H%M%S).log"
 
echo "exit=${PIPESTATUS[0]}"   # tee ではなく xcodebuild 側の終了コードを見ます

set -o pipefail と ${PIPESTATUS[0]} の二つがない状態でパイプを繋ぐと、判定されるのは tee の終了コードになります。つまり、ビルドが落ちても 0 が返ります。冒頭の報告とよく似た形を、自分の手で作り出してしまうことになるのです。

もう一つの沈黙は、0 バイトのファイルを「ある」と数えた存在チェックでした

ふたつめは、実機向けの EAS ビルドで作ったアプリが、起動した瞬間に dyld のクラッシュで終わるという報告です(expo/expo#50236)。ログに出るのは次の一行です。

Library not loaded: @rpath/ExpoModulesJSI.framework/ExpoModulesJSI

報告者は三段階の調査の末に、公式のビルドスクリプト create-stub-xcframework.sh に辿り着いています。そこでは、すでにスタブが作られているかどうかを -f で確かめていました。

-f は「通常ファイルとして存在するか」だけを見ます。中身が空でも、存在していれば真です。前の回のビルドが途中で落ちて 0 バイトのファイルを残していた場合、スクリプトは「もう作ってある」と判断して作り直さず、Embed Frameworks の段でも実体のないものが素通りします。アプリは出来上がり、実機で起動した瞬間に読み込めないと言われます。

修正は、判定を -s に変えるだけでした。

# 変更前: 存在すれば通す(0 バイトでも通ってしまいます)
if [ -f "$STUB_PATH" ]; then
  echo "stub already built"; exit 0
fi
 
# 変更後: 存在し、かつ空でないときだけ通します
if [ -s "$STUB_PATH" ]; then
  echo "stub already built ($(wc -c < "$STUB_PATH") bytes)"; exit 0
fi
 
# さらに安全側へ寄せるなら、壊れた残骸を先に片づけます
if [ -f "$STUB_PATH" ] && [ ! -s "$STUB_PATH" ]; then
  echo "found a zero-byte stub, removing it"
  rm -f "$STUB_PATH"
fi

一文字の差ですが、意味はまったく違います。よく使う判定の違いを並べておきます。

判定真になる条件ビルド生成物に使うとき
-e何らかの形で存在する(ディレクトリでも真)成果物の確認には弱すぎます
-f通常ファイルとして存在する(0 バイトでも真)中断した前回の残骸を通してしまいます
-s存在し、かつサイズが 0 より大きいキャッシュ判定はここから始めます
-dディレクトリとして存在する.xcframework や .app はこちらで見ます

.xcframework や .app はディレクトリですから、-s では測れません。中の実体を名指しして確かめるほうが確実です。

# .xcframework はディレクトリなので、中のバイナリを直接見ます
FW="build/ExpoModulesJSI.xcframework"
BIN=$(find "$FW" -name 'ExpoModulesJSI' -type f -size +0 2>/dev/null | head -1)
 
if [ -z "$BIN" ]; then
  echo "xcframework is present but empty — rebuilding" >&2
  rm -rf "$FW"
else
  echo "ok: $BIN ($(wc -c < "$BIN") bytes)"
fi

この二件には、Bot が「再現手順が足りない」として自動的に閉じたという共通点もあります。再現手順も原因も本文に書かれているのに閉じられていますので、同じ症状で検索した方が「解決済み」と読み違えないよう、issue 番号を添えて残しておきます。

自分のスクリプトを 10 分で棚卸しする

個人開発でアプリを何本か抱えていますと、ビルドを回すたびに流れる大量の行が邪魔になり、どこかの時点で -q や 2>/dev/null を足したくなります。私自身、配信まわりのスクリプトにそうした指定を足したことが何度もあります。足した当日は快適ですが、半年後に原因の見えない失敗として返ってきます。

順番はこうしています。

  1. 出力を減らしている箇所を数えます。
grep -rnE -- '-quiet|(^| )-q( |$)|2>\s*/dev/null|&>\s*/dev/null|> */dev/null' \
  scripts/ ios/ .github/ 2>/dev/null
  1. 見つかった行のうち、失敗しうるコマンドに付いているものだけを残します。echo や which を黙らせるのは無害です。xcodebuild・pod install・gradle・codesign の類は、黙らせた瞬間に診断の手がかりを失います。

  2. 成果物の存在チェックを洗います。

grep -rnE '\[ +-f +"?\$' scripts/ ios/ 2>/dev/null
  1. 残したい沈黙には、逃がし先を作ります。画面に出さない代わりに、必ずファイルへ落とします。
LOG="/tmp/ios-build-$(date +%s).log"
if ! xcodebuild -quiet ... build > "$LOG" 2>&1; then
  echo "build failed. last 40 lines:" >&2
  tail -40 "$LOG" >&2          # 黙らせても、落ちたときだけは喋らせます
  exit 1
fi
  1. 最後に、0 バイトのファイルが成果物ディレクトリに残っていないかを見ます。
find ios/build -type f -size 0 2>/dev/null

この 5 手順は、ビルドが通っている日にこそ回す価値があります。壊れてから探すと、どこまでが正常だったのかが分からなくなるためです。依存そのものの版が思い込みとずれていないかは、30日で9回出た Expo のパッチのうち、自分のアプリに入っているのはどれかを確かめるに書きました。アップロードされる範囲の思い込みについては、.easignore を置くと .gitignore は読まれなくなりますが近い話になります。

出力を減らすなら、逃がし先を必ず一つ作ります

二つの報告を並べて気づいたのは、どちらも「間違ったことをした」わけではない、ということでした。-quiet は行数を減らすための正当な指定ですし、-f はファイルの存在を確かめる素直な書き方です。問題が起きたのは、減らした情報の行き先を用意していなかった一点に尽きます。

最初のうち、私はログを短くすることをそのまま改善だと考えておりました。結果は芳しくありませんでした。短くした分だけ、失敗したときに見るものが無くなっていたのです。いまは一つだけ線を引いています。

黙らせてよいのは、落ちたときに喋り直せるようにしてある箇所だけです。

この線引きは、Rork から書き出したプロジェクトに限った話ではありません。ストアへ出すまでの道のりでは、手元の Mac・CI・EAS と、ログの置き場所が何度も変わります。変わるたびに、どこへ逃がしているのかを一つ決めておく必要があります。

次にビルドを回すときは、xcodebuild を呼んでいる行を一つ開いて、失敗した場合にその出力がどこへ行くのかだけを確かめてみてください。行き先が /dev/null になっていたら、そこを /tmp のファイルに書き換えるところから始めていただければと思います。私もそこから始めました。

最後までお読みくださり、ありがとうございました。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ 開発ツール2026-10-07
日本語の見出しだけ太字にならない — Android で fontWeight が効かないときの切り分けと直し方
Rork で作ったアプリで、iPhone では太字なのに Android では日本語の見出しが細いままになる症状の切り分け記事です。原因の見分け方、fontFamily を重みごとに分ける直し方、確認用コードを載せています。
⬡ 開発ツール2026-09-07
.easignore を置くと .gitignore は読まれなくなります — EAS Build に上がるファイルを手元で数える
EAS Build がアップロードする範囲は .gitignore で決まり、.easignore を置いた時点で入れ替わります。同梱ファイルを送信前に数える手順と、親ディレクトリを除外すると感嘆符では戻せないという実測結果をまとめました。
⬡ 開発ツール2026-09-05
Widget Extension でも BGTaskScheduler.submit は成功します。走らないのは register が親アプリだけのものだからです
Widget Extension から BGTaskScheduler に依頼を出すとビルドも submit も通るのに、翌朝ウィジェットは変わりません。register がホストアプリ専用である事実から、更新の主語を親アプリへ戻す設計まで、壁紙アプリの運用で詰めた手順を残します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます