Skip to content

fix: skip appIcon apply during CmuxSettingsFileStore init (fixes macOS 26 crash on launch) - #3100

Closed
KIT64 wants to merge 2 commits into
manaflow-ai:mainfrom
KIT64:fix/appicon-tahoe-init-timing
Closed

KIT64 wants to merge 2 commits into
manaflow-ai:mainfrom
KIT64:fix/appicon-tahoe-init-timing

Conversation

@KIT64

@KIT64 KIT64 commented Apr 22, 2026 •

Copy link
Copy Markdown

Summary

Fixes #3099 — deterministic crash on launch on macOS 26.3.1 (build 25D771280a+).

Root cause: On this build, applicationDidFinishLaunching fires before cmuxApp.init() body completes. @NSApplicationDelegateAdaptor stored properties are initialized before the init() body, which causes SwiftUI to wire up the delegate (and fire applicationDidFinishLaunching) before _ = KeyboardShortcutSettings.settingsFileStore runs. As a result, isApplicationFinishedLaunching() returns true while CmuxSettingsFileStore.init() is still executing, bypassing the existing guard in AppIconSettings.applyIcon and crashing at:

AppIconAppearanceObserver.applyIconForCurrentAppearance() + 648  ← brk #1
closure #3 in static AppIconSettings.Environment.live()
CmuxSettingsFileStore.applyManagedUserDefaultsValue(_:for:)
CmuxSettingsFileStore.init(primaryPath:fallbackPath:...)
cmuxApp.init()

Fix: Add isInitializationComplete flag to CmuxSettingsFileStore. Both applyManagedUserDefaultsValue and restoreUserDefaultsBackup now skip AppIconSettings.applyIcon while isInitializationComplete == false (i.e. during init()). AppDelegate.ensureApplicationIcon() handles the initial icon apply in applicationDidFinishLaunching, which is already the correct path.

Two-commit structure:

  1. Failing regression test (testSettingsFileStoreDoesNotApplyAppIconDuringInitEvenIfLaunchIsAlreadyFinished) — simulates macOS 26 by setting isApplicationFinishedLaunching: { true } and asserting no startAppearanceObservation calls during store init.
  2. Fix — isInitializationComplete flag.

Workaround (for users on macOS 26.3.1 until a fix ships)

Create ~/.config/cmux/settings.json with any non-automatic appIconMode:

{
  "$schema": "https://raw.githubusercontent.com/manaflow-ai/cmux/main/web/data/cmux-settings.schema.json",
  "appIconMode": "light"
}

Test plan

  • Unit test testSettingsFileStoreDoesNotApplyAppIconDuringInitEvenIfLaunchIsAlreadyFinished passes after the fix commit
  • Existing tests testSettingsFileStoreDoesNotApplyAutomaticAppIconDuringStartupReplay and testSettingsFileStoreCanReplayAutomaticAppIconSettingTwiceWithoutTouchingAppKit still pass
  • App icon still applies correctly after applicationDidFinishLaunching (via ensureApplicationIcon())
  • Runtime appIconMode changes in settings.json still take effect after app is running

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where app icon settings were being applied prematurely during startup, which could cause unintended appearance changes.
  • Tests

    • Added regression test to prevent recurrence of app icon initialization issue.

Summary by cubic

Fixes a deterministic crash on launch in macOS 26.3.1 by deferring app icon application during CmuxSettingsFileStore initialization; the initial icon now applies after applicationDidFinishLaunching.

  • Bug Fixes
    • Added isInitializationComplete flag set after the first reload(); applyManagedUserDefaultsValue and restoreUserDefaultsBackup skip AppIconSettings.applyIcon until initialization completes. AppDelegate.ensureApplicationIcon() applies the icon after launch.
    • Added regression test testSettingsFileStoreDoesNotApplyAppIconDuringInitEvenIfLaunchIsAlreadyFinished.

Written for commit 7ecb658. Summary will update on new commits.

KIT64 and others added 2 commits April 22, 2026 15:10
…store init

Simulates macOS 26 (build 25D771280a+) where applicationDidFinishLaunching
fires before cmuxApp.init() body completes, so isApplicationFinishedLaunching()
returns true while CmuxSettingsFileStore is still initializing.

The existing guard in AppIconSettings.applyIcon only blocks when the flag is
false; on affected macOS 26 builds the flag is already true, so applyIcon
proceeds to call startAppearanceObservation → applyIconForCurrentAppearance
→ NSApplication APIs that crash during App.init() re-entrancy.

This test currently FAILS (startObservationCallCount > 0).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…S 26 crash

On macOS 26 (build 25D771280a+), applicationDidFinishLaunching fires before
cmuxApp.init() body completes because @NSApplicationDelegateAdaptor stored
properties are initialized before the init body runs. This causes
isApplicationFinishedLaunching() to return true while CmuxSettingsFileStore
is still initializing, bypassing the existing guard in AppIconSettings.applyIcon.
The result is a deterministic crash at startup:

  AppIconAppearanceObserver.applyIconForCurrentAppearance() + 648
  closure manaflow-ai#3 in static AppIconSettings.Environment.live()
  CmuxSettingsFileStore.applyManagedUserDefaultsValue(_:for:)
  CmuxSettingsFileStore.init(...)

Add isInitializationComplete flag to CmuxSettingsFileStore. Both
applyManagedUserDefaultsValue and restoreUserDefaultsBackup now skip
AppIconSettings.applyIcon while the flag is false (i.e. during init).
AppDelegate.ensureApplicationIcon() handles the initial icon apply once
applicationDidFinishLaunching runs, which is already the correct path.

Fixes manaflow-ai#3099

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 22, 2026

Copy link
Copy Markdown

@KIT64 is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Apr 22, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c68edc63-d02e-48b6-871c-577a168673d1

📥 Commits

Reviewing files that changed from the base of the PR and between 3e84c16 and 7ecb658.

📒 Files selected for processing (2)
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • cmuxTests/WorkspaceUnitTests.swift

📝 Walkthrough

Walkthrough

The PR adds an isInitializationComplete flag to guard against app icon application during KeyboardShortcutSettingsFileStore initialization, preventing premature icon side effects. A regression test validates that icon-related operations are skipped during store init.

Changes

Cohort / File(s) Summary
Settings File Store Init Guard
Sources/KeyboardShortcutSettingsFileStore.swift
Added isInitializationComplete boolean flag tracked during first reload(). Updated applyManagedUserDefaultsValue and restoreUserDefaultsBackup to skip AppIconSettings.applyIcon(...) invocation until initialization completes.
Regression Test
cmuxTests/WorkspaceUnitTests.swift
Added testSettingsFileStoreDoesNotApplyAppIconDuringInitEvenIfLaunchIsAlreadyFinished() to verify that app icon side effects (appearance observation and icon application) are not triggered when KeyboardShortcutSettingsFileStore is initialized with automatic icon mode, even with launch signaling complete.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Poem

🐰 A flag takes guard at init's door,
No icons bloom 'til setup's more!
The rabbit hops through launch's maze,
No crashes now—just cleaner days! 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the fix: skipping appIcon application during CmuxSettingsFileStore initialization to prevent the macOS 26 crash.
Description check ✅ Passed The description thoroughly documents the root cause, fix, workaround, and test plan, matching the template's Summary and Testing sections.
Linked Issues check ✅ Passed The PR successfully addresses all coding objectives from issue #3099: prevents AppIconAppearanceObserver from running during store init by adding isInitializationComplete flag, ensures initial icon application via AppDelegate.ensureApplicationIcon(), and maintains runtime settings changes.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the initialization crash: isInitializationComplete flag in KeyboardShortcutSettingsFileStore, guard conditions in applyManagedUserDefaultsValue and restoreUserDefaultsBackup, and a focused regression test.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a deterministic crash on macOS 26.3.1 (build 25D771280a+) where applicationDidFinishLaunching fires before cmuxApp.init() body completes, causing AppIconSettings.applyIcon to call unsafe NSApplication APIs while the app is still initializing. The fix introduces an isInitializationComplete flag on CmuxSettingsFileStore that guards both applyManagedUserDefaultsValue and restoreUserDefaultsBackup from touching the app icon during init(), delegating the initial icon apply to AppDelegate.ensureApplicationIcon(). The two-commit structure (failing test first, fix second) correctly follows the repository's regression test policy from CLAUDE.md.

Confidence Score: 5/5

Safe to merge — minimal, targeted fix with a dedicated regression test and no observable behavior change on unaffected code paths.

The change is a narrow, two-line guard addition with no effect on post-init behavior. The regression test correctly simulates the macOS 26 re-entrancy condition and validates the fix. Existing tests for the startup-replay and double-replay scenarios continue to pass. No P0/P1 findings.

No files require special attention.

Important Files Changed

Filename Overview
Sources/KeyboardShortcutSettingsFileStore.swift Adds isInitializationComplete flag set after the first reload() in init(); guards two AppIconSettings.applyIcon call sites in applyManagedUserDefaultsValue and restoreUserDefaultsBackup to skip icon application until initialization is fully complete.
cmuxTests/WorkspaceUnitTests.swift Adds regression test testSettingsFileStoreDoesNotApplyAppIconDuringInitEvenIfLaunchIsAlreadyFinished that simulates macOS 26 by returning true from isApplicationFinishedLaunching and asserts no appearance observation or icon set calls occur during store init.

Sequence Diagram

sequenceDiagram
    participant SwiftUI as SwiftUI Runtime
    participant App as cmuxApp.init()
    participant Store as CmuxSettingsFileStore.init()
    participant AppDelegate as AppDelegate
    participant AppIcon as AppIconSettings

    SwiftUI->>App: init() begins
    Note over App: @NSApplicationDelegateAdaptor stored props init'd first
    SwiftUI->>AppDelegate: applicationDidFinishLaunching (macOS 26: fires early)
    Note over AppDelegate: isApplicationFinishedLaunching() → true

    App->>Store: init() begins
    Store->>Store: bootstrapPrimaryTemplateIfNeeded()
    Store->>Store: reload() → applyManagedUserDefaultsValue(appIconMode)
    Store->>Store: guard isInitializationComplete else break ✅ (skips applyIcon)
    Store->>Store: isInitializationComplete = true
    Store-->>App: init() complete

    AppDelegate->>AppIcon: ensureApplicationIcon() → applyIcon() ✅ (safe path)
Loading

Reviews (1): Last reviewed commit: "fix: skip appIcon apply during CmuxSetti..." | Re-trigger Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Thanks for this! The settings-store init no longer applies side effects like the app icon landed on main in #4353. You opened this first, so you got there first. Closing since main covers it now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash on launch (macOS 26 Tahoe): AppIconAppearanceObserver.applyIconForCurrentAppearance() with appIconMode=automatic

2 participants