home / skills / derklinke / codex-config / ios-xcode-debugging

ios-xcode-debugging skill

/skills/ios-xcode-debugging

This skill guides you through environment-first Xcode diagnostics to resolve builds, simulators, and Derived Data issues before touching code.

npx playbooks add skill derklinke/codex-config --skill ios-xcode-debugging

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.9 KB
---
name: xcode-debugging
description: Use when encountering BUILD FAILED, test crashes, simulator hangs, stale builds, zombie xcodebuild processes, "Unable to boot simulator", "No such module" after SPM changes, or mysterious test failures despite no code changes - systematic environment-first diagnostics for iOS/macOS projects
skill_type: discipline
version: 1.0.0
# MCP annotations (ignored by Claude Code)
mcp:
  category: debugging
  tags: [xcode, build, simulator, environment, diagnostics]
  related: [swift-concurrency-expert, swift-testing]
---

# Xcode Debugging

## Overview

Check build environment BEFORE debugging code. **Core principle** 80% of "mysterious" Xcode issues are environment problems (stale Derived Data, stuck simulators, zombie processes), not code bugs.

## Example Prompts

These are real questions developers ask that this skill is designed to answer:

#### 1. "My build is failing with 'BUILD FAILED' but no error details. I haven't changed anything. What's going on?"

→ The skill shows environment-first diagnostics: check Derived Data, simulator states, and zombie processes before investigating code

#### 2. "Tests passed yesterday with no code changes, but now they're failing. This is frustrating. How do I fix this?"

→ The skill explains stale Derived Data and intermittent failures, shows the 2-5 minute fix (clean Derived Data)

#### 3. "My app builds fine but it's running the old code from before my changes. I restarted Xcode but it still happens."

→ The skill demonstrates that Derived Data caches old builds, shows how deletion forces a clean rebuild

#### 4. "The simulator says 'Unable to boot simulator' and I can't run tests. How do I recover?"

→ The skill covers simulator state diagnosis with simctl and safe recovery patterns (erase/shutdown/reboot)

#### 5. "I'm getting 'No such module: SomePackage' errors after updating SPM dependencies. How do I fix this?"

→ The skill explains SPM caching issues and the clean Derived Data workflow that resolves "phantom" module errors

---

## Red Flags — Check Environment First

If you see ANY of these, suspect environment not code:

- "It works on my machine but not CI"
- "Tests passed yesterday, failing today with no code changes"
- "Build succeeds but old code executes"
- "Build sometimes succeeds, sometimes fails" (intermittent failures)
- "Simulator stuck at splash screen" or "Unable to install app"
- Multiple xcodebuild processes (10+) older than 30 minutes

## Mandatory First Steps

**ALWAYS run these commands FIRST** (before reading code):

```bash
# 1. Check processes (zombie xcodebuild?)
ps aux | grep -E "xcodebuild|Simulator" | grep -v grep

# 2. Check Derived Data size (>10GB = stale)
du -sh ~/Library/Developer/Xcode/DerivedData

# 3. Check simulator states (stuck Booting?)
xcrun simctl list devices | grep -E "Booted|Booting|Shutting Down"
```

#### What these tell you

- **0 processes + small Derived Data + no booted sims** → Environment clean, investigate code
- **10+ processes OR >10GB Derived Data OR simulators stuck** → Environment problem, clean first
- **Stale code executing OR intermittent failures** → Clean Derived Data regardless of size

#### Why environment first

- Environment cleanup: 2-5 minutes → problem solved
- Code debugging for environment issues: 30-120 minutes → wasted time

## Quick Fix Workflow

### Finding Your Scheme Name

If you don't know your scheme name:

```bash
# List available schemes
xcodebuild -list
```

### For Stale Builds / "No such module" Errors

```bash
# Clean everything
xcodebuild clean -scheme YourScheme
rm -rf ~/Library/Developer/Xcode/DerivedData/*
rm -rf .build/ build/

# Rebuild
xcodebuild build -scheme YourScheme \
  -destination 'platform=iOS Simulator,name=iPhone 16'
```

### For Simulator Issues

```bash
# Shutdown all simulators
xcrun simctl shutdown all

# If simctl command fails, shutdown and retry
xcrun simctl shutdown all
xcrun simctl list devices

# If still stuck, erase specific simulator
xcrun simctl erase <device-uuid>

# Nuclear option: force-quit Simulator.app
killall -9 Simulator
```

### For Zombie Processes

```bash
# Kill all xcodebuild (use cautiously)
killall -9 xcodebuild

# Check they're gone
ps aux | grep xcodebuild | grep -v grep
```

### For Test Failures

```bash
# Isolate failing test
xcodebuild test -scheme YourScheme \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -only-testing:YourTests/SpecificTestClass
```

## Simulator Verification (Optional)

After applying fixes, verify in simulator with visual confirmation.

### Quick Screenshot Verification

```bash
# 1. Boot simulator (if not already)
xcrun simctl boot "iPhone 16 Pro"

# 2. Build and install app
xcodebuild build -scheme YourScheme \
  -destination 'platform=iOS Simulator,name=iPhone 16 Pro'

# 3. Launch app
xcrun simctl launch booted com.your.bundleid

# 4. Wait for UI to stabilize
sleep 2

# 5. Capture screenshot
xcrun simctl io booted screenshot /tmp/verify-build-$(date +%s).png
```

### Using Tools

**Quick screenshot**:

```bash
/screenshot
```

**Full simulator testing** (with navigation, state setup):

```bash
/test-simulator
```

### When to Use Simulator Verification

Use when:

- **Visual fixes** — Layout changes, UI updates, styling tweaks
- **State-dependent bugs** — "Only happens in this specific screen"
- **Intermittent failures** — Need to reproduce specific conditions
- **Before shipping** — Final verification that fix actually works

**Pro tip**: If you have debug deep links (see `deep-link-debugging` skill), you can navigate directly to the screen that was broken:

```bash
xcrun simctl openurl booted "debug://problem-screen"
sleep 1
xcrun simctl io booted screenshot /tmp/fix-verification.png
```

## Decision Tree

```
Test/build failing?
├─ BUILD FAILED with no details?
│  └─ Clean Derived Data → rebuild
├─ Build intermittent (sometimes succeeds/fails)?
│  └─ Clean Derived Data → rebuild
├─ Build succeeds but old code executes?
│  └─ Delete Derived Data → rebuild (2-5 min fix)
├─ "Unable to boot simulator"?
│  └─ xcrun simctl shutdown all → erase simulator
├─ "No such module PackageName"?
│  └─ Clean + delete Derived Data → rebuild
├─ Tests hang indefinitely?
│  └─ Check simctl list → reboot simulator
├─ Tests crash?
│  └─ Check ~/Library/Logs/DiagnosticReports/*.crash
└─ Code logic bug?
   └─ Switch to code-level debugging (framework- or feature-specific skill)
```

## Common Error Patterns

| Error | Fix |
|-------|-----|
| `BUILD FAILED` (no details) | Delete Derived Data |
| `Unable to boot simulator` | `xcrun simctl erase <uuid>` |
| `No such module` | Clean + delete Derived Data |
| Tests hang | Check simctl list, reboot simulator |
| Stale code executing | Delete Derived Data |

## Useful Flags

```bash
# Show build settings
xcodebuild -showBuildSettings -scheme YourScheme

# List schemes/targets
xcodebuild -list

# Verbose output
xcodebuild -verbose build -scheme YourScheme

# Build without testing (faster)
xcodebuild build-for-testing -scheme YourScheme
xcodebuild test-without-building -scheme YourScheme
```

## Crash Log Analysis

```bash
# Recent crashes
ls -lt ~/Library/Logs/DiagnosticReports/*.crash | head -5

# Symbolicate address (if you have .dSYM)
atos -o YourApp.app.dSYM/Contents/Resources/DWARF/YourApp \
  -arch arm64 0x<address>
```

## Common Mistakes

❌ **Debugging code before checking environment** — Always run mandatory steps first

❌ **Ignoring simulator states** — "Booting" can hang 10+ minutes, shutdown/reboot immediately

❌ **Assuming git changes caused the problem** — Derived Data caches old builds despite code changes

❌ **Running full test suite when one test fails** — Use `-only-testing` to isolate

## Real-World Impact

**Before** 30+ min debugging "why is old code running"
**After** 2 min environment check → clean Derived Data → problem solved

**Key insight** Check environment first, debug code second.

Overview

This skill provides an environment-first diagnostic workflow for iOS/macOS Xcode problems. It focuses on quick checks and fixes for common issues like BUILD FAILED, simulator hangs, stale Derived Data, zombie xcodebuild processes, and SPM "No such module" errors. Use it to rule out environment causes before diving into code debugging.

How this skill works

The skill runs a short set of mandatory checks: list xcodebuild/Simulator processes, measure Derived Data size, and inspect simulator states via simctl. Based on those signals it recommends targeted actions (clean Derived Data, kill zombie processes, shutdown/erase simulators, or rebuild). It includes quick shell commands and a decision tree so you can resolve most mysterious failures in 2–5 minutes instead of hours.

When to use it

  • Build shows "BUILD FAILED" with no useful error output
  • Tests passed previously but now fail with no code changes
  • App runs old code after changes or intermittent build successes
  • Simulator reports "Unable to boot simulator" or is stuck booting/shutting down
  • You see many old xcodebuild processes or very large Derived Data (>10GB)
  • After updating SPM dependencies you get "No such module" errors

Best practices

  • Always run the mandatory environment commands before reading or modifying code
  • Prefer deleting Derived Data and rebuilding for stale or intermittent failures
  • Use simctl to inspect and control simulator state before force-quitting the Simulator app
  • Kill zombie xcodebuild processes cautiously and re-run the build to confirm a clean slate
  • Isolate tests with -only-testing instead of running the full suite to reproduce failures quickly

Example use cases

  • Quickly recover when CI shows a build failure that doesn't reproduce locally by checking Derived Data and processes
  • Fix "No such module" after SPM changes by cleaning and deleting Derived Data, then rebuilding
  • Recover from "Unable to boot simulator" by shutting down/erasing the problematic device with xcrun simctl
  • Stop intermittent test failures by isolating the failing test with xcodebuild -only-testing and ensuring simulator state is clean
  • Resolve stale code execution after changes by removing Derived Data and performing a clean rebuild

FAQ

What are the absolute first commands I should run?

Check processes, Derived Data size, and simulator states: ps aux | grep -E "xcodebuild|Simulator"; du -sh ~/Library/Developer/Xcode/DerivedData; xcrun simctl list devices | grep -E "Booted|Booting|Shutting Down".

When should I delete Derived Data?

Delete Derived Data whenever builds run old code, failures are intermittent, or you see >10GB of Derived Data. It’s a 2–5 minute fix that resolves many phantom errors.

How do I handle persistent simulator boot failures?

Shutdown all sims (xcrun simctl shutdown all), try xcrun simctl list devices, erase the specific device (xcrun simctl erase <uuid>), and as a last resort killall -9 Simulator.