Skip to content

Fix crash when a rule's target app is uninstalled, and restore the build on current SDKs - #63

Open
matijazezelj wants to merge 2 commits into
AlexStrNik:mainfrom
matijazezelj:fix/crash-on-missing-app
Open

matijazezelj wants to merge 2 commits into
AlexStrNik:mainfrom
matijazezelj:fix/crash-on-missing-app

Conversation

@matijazezelj

@matijazezelj matijazezelj commented Sep 11, 2026

Copy link
Copy Markdown

Two independent fixes. The first one currently stops main from building at all.

1. main no longer compiles against current SDKs

Browserino/Extensions/View+ScrollEdgeDisabled.swift:16 calls scrollEdgeEffectDisabled(_:for:). That API has been renamed to scrollEdgeEffectHidden(_:for:). The old symbol survives in SwiftUI.tbd for ABI compatibility, but it is absent from the .swiftinterface of both the macOS 26.5 and macOS 27.0 SDKs, so the call no longer type-checks:

View+ScrollEdgeDisabled.swift:16:18: error: value of type 'some View' has no member 'scrollEdgeEffectDisabled'
View+ScrollEdgeDisabled.swift:16:55: error: cannot infer contextual base in reference to member 'all'

scrollEdgeEffectHidden(_:for:) is declared @available(iOS 26.0, macOS 26.0, tvOS 26.0, watchOS 26.0, *) — identical to what the existing if #available(macOS 26.0, *) guard already checks — so it drops in with no other change.

2. Crash when a rule points at an app that is no longer installed

Browserino/Views/Preferences/RulesTab.swift:47 force-unwrapped Bundle(url: rule.app)!. Bundle(url:) returns nil as soon as the target app is renamed, moved or uninstalled, so the Rules tab traps the instant its List lays that row out:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Termination:     Trace/BPT trap: 5

closure #1 in ViewBodyAccessor.updateBody(of:changed:)
NSHostingView._willUpdateConstraintsForSubtree()
-[NSTableRowData _doAutomaticRowHeightForRowView:row:]
-[NSTableView layout]

I hit this when Zen Browser renamed its bundle from Zen Browser.app to Zen.app. What makes it worse than a normal crash is that it is unrecoverable from the UI: a stale rule can only be removed from the Rules tab, and opening the Rules tab is exactly what kills the app. The only way out is editing defaults by hand.

Rows whose app cannot be resolved now render in a degraded state instead — greyed-out name with a placeholder icon — keeping their edit affordance so the rule can be repointed or deleted:

  ✏  https://.*foo                          Chrome    [icon]
  ✏  https://.*bar          Zen Browser (not installed)   [?]

The same treatment is applied to CFBundleName and bundleIdentifier — both genuinely optional in shipping app bundles — and to the equivalent sites in the Apps tab, Browsers tab and the picker. Note the Apps tab previously hid unresolvable rows behind if let, which produces the same dead end in a quieter way: an entry you can neither see nor delete.

Verification

  • Both fixes compile clean (0 errors) with the Swift 6.4 toolchain against the macOS 26.5 SDK, targeting macOS 14.0. For reference, unmodified origin/main fails with the 4 errors quoted above.
  • The crash fix was verified at runtime, not just type-checked: I hosted the real RulesTab in an NSWindow seeded with a rule pointing at a non-existent bundle, so the actual NSTableView row-height path that produced the trace above gets exercised. Both rows lay out, nothing traps.
  • The resulting app has been running as my default browser on macOS 27.

No behaviour changes beyond the above — no reformatting, no unrelated refactors.

Disclosure

This was written with AI assistance (Claude Code). The starting point was a real crash report from my own machine, and everything above was compiled and the crash path verified at runtime before I opened this. Happy to adjust anything to taste.

matijazezelj and others added 2 commits September 11, 2026 20:31
Bundle(url:) returns nil once an app is moved, renamed or uninstalled, so
force-unwrapping it in RuleItem.body trapped the moment the Rules tab laid
out its List — making a stale rule impossible to reach and delete.

Rows for unresolved apps now render in a degraded state instead of being
force-unwrapped or hidden, so they can still be edited or removed. Apply the
same treatment to CFBundleName and bundleIdentifier, which are both optional
in practice, and to the equivalent sites in the Apps tab, Browsers tab and
the picker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWQa3xpkwVRtrtVh8VkQQo
The symbol survives in SwiftUI.tbd but is absent from the swiftinterface of
both the macOS 26.5 and 27.0 SDKs, so the call no longer compiles against any
current SDK. scrollEdgeEffectHidden(_:for:) carries the same
@available(macOS 26.0, *) and slots straight into the existing guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWQa3xpkwVRtrtVh8VkQQo
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.

1 participant