CLAUDE LABJP
SWE-BENCH — Claude Opus 4.8 scores 69.2% on SWE-Bench Pro, topping GPT-5.5 and Gemini 3.1 Pro (May)TOKYO — Code with Claude heads to Tokyo on June 10, its first Asia stop after SF and London (Jun)LIMITS — Claude Code raises weekly limits by 50% for all Pro/Max/Team/Enterprise users through July 13 (Jun)EFFORT — claude.ai now lets users control how much effort Claude puts into a task (Jun)SPEED — Opus 4.8's fast mode runs 2.5x faster at the same price as Opus 4.7 (May)WORKFLOW — Claude Code's Dynamic Workflows distribute work across hundreds of parallel subagents (May)SWE-BENCH — Claude Opus 4.8 scores 69.2% on SWE-Bench Pro, topping GPT-5.5 and Gemini 3.1 Pro (May)TOKYO — Code with Claude heads to Tokyo on June 10, its first Asia stop after SF and London (Jun)LIMITS — Claude Code raises weekly limits by 50% for all Pro/Max/Team/Enterprise users through July 13 (Jun)EFFORT — claude.ai now lets users control how much effort Claude puts into a task (Jun)SPEED — Opus 4.8's fast mode runs 2.5x faster at the same price as Opus 4.7 (May)WORKFLOW — Claude Code's Dynamic Workflows distribute work across hundreds of parallel subagents (May)
Articles/Claude Code
Claude Code/2026-06-04Intermediate

Clearing Crashlytics 'Missing dSYM' Warnings with Claude Code: A Field Memo

Right after moving Firebase to SPM, my Crashlytics reports stopped symbolicating and showed raw addresses. Here is how I narrowed down the Missing dSYM cause with Claude Code and rebuilt an upload path that does not break again.

Claude Code239Crashlytics8dSYMiOS26Firebase5indie developer12

A few days after shipping an update to one of my wallpaper apps, an unfamiliar row appeared in the Firebase Crashlytics dashboard. The crashes were being recorded, but every stack frame read like 0x0000000102f4c8a8 — just an address. There was no way to tell which function had failed or on which line. At the top sat a yellow "Missing dSYM" warning. I had a hunch about the cause: shortly before, I had moved Firebase from CocoaPods to Swift Package Manager.

Staring at that wall of hex, I thought of my two grandfathers, both temple carpenters. A joint that skips its finishing work looks fine from the outside, but the warp always shows up later. Crash reports are the same. Skip the unglamorous finishing step of symbolication, and the one time a user is actually in trouble, the part you need most is unreadable. After running my own apps since 2014, this "it runs but it is not finished" state is the one I fear most. This time I rebuilt that symbolication step, with Claude Code helping, until it passed reliably.

What a dSYM Actually Does

A dSYM (debug symbols) file is a dictionary that maps the function names, file names, and line numbers stripped from a release build back to the memory addresses in the executable. When a crash happens, Crashlytics collects the addresses and later consults this dictionary to restore something readable, like applyFilter(_:) at WallpaperViewModel.swift:142. That restoration is symbolication.

The mapping between the dictionary and the binary is keyed by UUID. So if the dSYM that reaches Crashlytics was not generated from the exact same build you shipped, the UUIDs will not line up and you get "Missing dSYM." Put the other way around: the cause is always one of two things — the dSYM was never created, or it was created but never delivered. Settling that split first was the shortest path through the problem.

Narrowing It to Two Options with Claude Code

I launched Claude Code from the terminal and started by handing it the UUID shown in the warning. Crashlytics tells you exactly which dSYM UUID it is missing, so the first job is to check whether that UUID exists locally. macOS has a built-in way to look up a dSYM by UUID.

# Find the UUID that Crashlytics is asking for, locally
mdfind "com_apple_xcode_dsym_uuids == E1B2C3D4-5678-90AB-CDEF-1234567890AB"
 
# Inspect the dSYM UUID inside the archive directly
dwarfdump --uuid ~/Library/Developer/Xcode/Archives/2026-06-01/MyApp.xcarchive/dSYMs/*.dSYM

This told me the dSYM had in fact been generated correctly inside the archive. So this was not the "never created" case — it was the "never delivered" case. The moment the cause collapsed to one of two options, the search space shrank dramatically. When I told Claude Code "the archive has a matching-UUID dSYM, so it is generated but not uploaded, and I suspect the SPM move changed the run script path," it proceeded on exactly that premise — which is one of the most fragile spots in an SPM migration.

The Run Script Path Had Changed in the SPM Move

Under CocoaPods, Crashlytics called Pods/FirebaseCrashlytics/run from a Build Phase script. Once you move to SPM, the Pods directory is gone, so a script still pointing at that old path simply does nothing. The nasty part is that it fails silently — the build stays green.

The correct SPM path points at the firebase-ios-sdk checkout under the build directory. I added a fresh Run Script in Build Phases and declared its input files explicitly.

# Build Phases > Run Script (SPM version of Crashlytics)
"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run"

In the Input Files section, pass the locations of the dSYM and the Info.plist. Leave this empty and the new build system may skip the script entirely.

${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}
$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)

I also confirmed that Debug Information Format for the Release configuration was set to DWARF with dSYM File. If it is set to plain DWARF, the dSYM is never produced in the first place. My project was fine here, but another of my wallpaper apps had this setting dropped only on Release — the textbook "never created" case. Same symptom, opposite cause.

Sending the Ones You Already Missed

Fixing the run script does not retroactively send the dSYMs for builds already on the store. Those you have to send by hand, calling the SPM version of upload-symbols directly.

# Use the upload-symbols binary from the SPM checkout
UPLOAD="$(find ~/Library/Developer/Xcode/DerivedData -name upload-symbols -path '*firebase-ios-sdk*' | head -1)"
 
"$UPLOAD" -gsp ./MyApp/GoogleService-Info.plist -p ios \
  ~/Library/Developer/Xcode/Archives/2026-06-01/MyApp.xcarchive/dSYMs

When I have Claude Code assemble this, I usually ask it to "turn this into a small loop that processes several apps' archives at once." I run several apps in parallel, mostly wallpaper and relaxation titles, so sending them one at a time guarantees I will miss some. Walking the archive list and sending only the unsent ones made this easy to fold into the monthly update routine.

# Process recent archives in order (swap the plist per app)
for ARCHIVE in ~/Library/Developer/Xcode/Archives/2026-*/*.xcarchive; do
  echo "▶ $(basename "$ARCHIVE")"
  "$UPLOAD" -gsp ./MyApp/GoogleService-Info.plist -p ios "$ARCHIVE/dSYMs" || echo "  skip"
done

After sending, it takes a while before the Crashlytics dashboard reflects the change. Do not resend repeatedly just because symbolication is not instant — waiting tens of minutes to a few hours is the right move. I once got impatient here and sent duplicates, which doubled the logs and made everything harder to verify. I will leave that here as a note to myself.

Letting Claude Code Read the Crash, Too

Once symbolication works, the stack trace reads in function names and line numbers — and this is exactly where Claude Code earns its keep. I paste the symbolicated trace and ask it to "name the conditions under which this crash fires and point to the likely spot." With raw addresses, any AI is just guessing; with function names and line numbers, it can actually open the relevant file and narrow down a hypothesis.

This particular crash came from image-filter code touching the UI off the main thread. Because the symbolicated trace showed applyFilter(_:), Claude Code opened the corresponding view model and flagged that the @MainActor guarantee was being dropped there. Had it stayed as raw addresses, I would probably have spent hours looking in the wrong place.

What I Will Do Next Time I See This Warning

If "Missing dSYM" shows up again, here is my order of operations. First, match the warning's UUID against my machine with mdfind and dwarfdump to settle whether it was "never created" or "never delivered." For the former, suspect the Release Debug Information Format; for the latter, suspect the run script path and Input Files. Run the manual upload exactly once, then wait for it to register. Just having that order decided keeps me from falling into the same pit twice.

The quiet finishing steps are the ones that pay off later. Keeping your crash reports readable is what lets you act before a user quietly walks away. If this adds one line to the monthly checklist of anyone juggling several apps the way I do, I will be glad.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-06-01
Moving Firebase From CocoaPods to SPM With Claude Code as a Partner: An Implementation Memo
A record of migrating Firebase from CocoaPods to Swift Package Manager in an indie iOS app. What I handed to Claude Code, what I decided myself, and the Crashlytics dSYM trap I hit along the way.
Claude Code2026-05-24
Automating iOS Crashlytics Triage with Claude Code — A Production Pipeline from dSYM Symbolication to Draft PR
How I rebuilt iOS crash triage at our 50M+ download app studio: Firebase Crashlytics issues flow into a Cloud Functions + Claude Code pipeline that handles dSYM symbolication, blast-radius estimation, and a draft fix PR in under 90 seconds. Real numbers, real code, real lessons.
Claude Code2026-05-23
Three Months of Letting Claude Code Handle the Monthly Content Refresh for My Four Wallpaper Apps
Starting in February 2026 I began handing off the monthly content refresh of my wallpaper apps — Beautiful HD Wallpapers and three sibling titles — to Claude Code. After three months I want to share what kinds of judgement I felt comfortable delegating, and where I deliberately kept my own hands on the work.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →