A little after you press submit, a red notice appears in the App Store tab. Open the log and several hundred lines of English come pouring down.
Rork's docs say to copy the entire log, paste it into Rork, and ask it to fix the build. I did exactly that. It did not work. The second time, the third time, the same red line sat at the bottom.
Here is the thing I would say first: pasting more times rarely helps. The docs say it usually resolves in one or two rounds, so once you are into a third, I think it is faster to check, before pasting again, where in the log you are actually looking.
The Last Red Line Is a Result, Not a Cause
In a long build log, the first error brings the next ones with it. If a package cannot be resolved, compiling, archiving and uploading all fail after it. "BUILD FAILED" and "UPLOAD FAILED" at the bottom are just the last link in that chain.
I had a habit of reading long logs from the bottom, because the bottom is what the screen shows you. But the cause is usually higher up, at the first line that says "error".
One caveat. Rork's submission-errors page does not quote exact error messages. It gives categories of causes and a fix routine. So the script below does not depend on any particular wording. It only looks for generic markers such as "error", "FAILED" and "ITMS-".
Pull Out the First Error and Its Neighbors
The idea is simple. Read the log from the top, find the first line that looks like an error, and print only that line and its surroundings. Summary lines such as "0 errors" and warnings are skipped.
#!/usr/bin/env python3
"""提出ログの「最初のエラー」と、その前後だけを取り出す。
使い方: python3 log_first_error.py build.log
"""
import re
import sys
# 「エラーの始まり」を示す語。0 errors のような集計行は除く
START = re.compile(r"(error:|\bERROR\b|\bFAILED\b|ITMS-\d+|Could not resolve|Execution failed)")
SKIP = re.compile(r"(\b0 errors?\b|no errors?|warning:)", re.I)
# Rork のドキュメントが挙げている4つの原因に対応する目印
BUCKETS = {
"権限の説明文が足りない": re.compile(r"(UsageDescription|purpose string|ITMS-90683)", re.I),
"パッケージの解決に失敗": re.compile(r"(Package\.resolved|dependenc(y|ies).*resolve|resolve.*package|version solving)", re.I),
"Capability が未承認": re.compile(r"(capabilit|entitlement|provisioning profile)", re.I),
"ID・バージョンの不一致": re.compile(r"(bundle identifier|CFBundle(Short)?Version|build number|already been used)", re.I),
}
def main(path: str) -> int:
lines = open(path, encoding="utf-8", errors="replace").read().splitlines()
first = next((i for i, ln in enumerate(lines)
if START.search(ln) and not SKIP.search(ln)), None)
if first is None:
print("エラーらしい行が見つかりません。ログが途中で切れていないか確認してください。")
return 1
lo, hi = max(0, first - 5), min(len(lines), first + 11)
print(f"最初のエラー: {first + 1} 行目 / 全 {len(lines)} 行")
print("-" * 40)
for n in range(lo, hi):
mark = ">>" if n == first else " "
print(f"{mark} {n + 1:>5}: {lines[n]}")
print("-" * 40)
window = "\n".join(lines[lo:hi])
hits = [name for name, rx in BUCKETS.items() if rx.search(window)]
print("目印に当たった原因: " + (" / ".join(hits) if hits else "なし(上の行を直接読む)"))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1]) if len(sys.argv) == 2 else print(__doc__) or 2)Save the log from the App Store tab to a text file and run python3 log_first_error.py build.log. If you do not have Python, opening the log in an editor and searching for "error" gives you the same first hit.
Why 5 lines before and 10 after? Just before an error you often find what the build was trying to do, and just after it, what was missing. The window is my own preference, so adjust it to how dense your logs are.
What It Printed on a Mock Log
I tested this on a mock log of about 300 lines that I wrote myself, not on real Rork output. It imitates a missing permission description in Info.plist.
First error: line 244 / 299 lines total
----------------------------------------
242: [0242] Archive succeeded
243: [0243] Uploading to App Store Connect...
>> 244: [0244] ERROR: Validation failed (409)
245: [0245] ITMS-90683: Missing purpose string in Info.plist. ...
246: [0246] NSCameraUsageDescription is not set.
247: [0247] ** UPLOAD FAILED **
----------------------------------------
Matched cause: missing permission description(The script itself prints these labels in Japanese; the English above is a translation of its output.)
If you had looked only at "UPLOAD FAILED", you would not even notice that the archive succeeded. Reading from the first error shows that the build passed and the upload validation is what stopped. That alone changes your request to the AI from "fix the build" to "add the camera usage description to Info.plist."
A second mock log, imitating a package conflict, surfaced "Dependencies could not be resolved" on line 101 as the first error. For a short log with no error-like line at all, the script says to check whether the log was cut off. That last behavior is a safety net for copies that stop partway.
Four Causes and Where to Look
Rork's docs list four typical causes of a build error. Which one your first error resembles tells you where to look.
| Cause | Markers in the log | Where to look first |
|---|---|---|
| A permission key is missing from Info.plist | purpose string, UsageDescription, ITMS-90683 | Which features the app uses (camera, photos, location) versus the keys in Info.plist |
| A Swift package fails to resolve, or two need different versions | resolve, dependencies, version | The two conflicting package names and the versions each one asks for |
| A capability is not enabled on the Apple Developer account | capability, entitlement, provisioning profile | The Capabilities section for the app under Identifiers in Apple Developer |
| Bundle ID or version does not match App Store Connect | bundle identifier, CFBundleVersion, build number | The ID registered in App Store Connect against the one in the app settings |
The docs also cover one more case: a build for the same version is already in review. Apple allows one build per version in review, so you either replace that build or raise the version number and resubmit. No error need appear in the log, yet the app never shows up in App Store Connect.
I wrote about how to phrase permission descriptions in Apple's automated pass reads what your purpose strings are for, not whether they exist. For telling which layer a stalled submission is stuck in, see When Rork Max's Two-Click Submit Stalls, Tell Which Layer Broke.
Handing It Back to the AI
Once you have a suspect, tidy what you paste. I do not drop the official advice to paste the whole log, because partial logs can hide the root cause. So I add a short preface above the full log.
My App Store submission failed. The full log is below.
The first error is ITMS-90683 on line 244 (a missing purpose string).
Please fix only what relates to that first error.
Leave the other warnings alone for now.
<full log here>The preface holds three things: the line number of the first error, the cause you suspect, and the scope you want fixed. When the AI knows where to start reading, it is less likely to be dragged along by the chained errors at the end.
What This Script Cannot Tell You
To be upfront: the markers only catch words I commonly see. If none of the four causes matches, the "matched cause" line says none, and you have to read the surrounding lines one by one yourself.
Also, what I verified on the mock logs is the script's behavior, not its hit rate on real Rork submission logs. I have not run into every cause listed here during my own submissions through Rork.
Before you paste again, read the first error aloud, one line. That is a rule I try to keep, especially on the tired nights when I want it over with.
The next time a submission stalls, start small: save the log to a file and find the first "error".