-
Notifications
You must be signed in to change notification settings - Fork 60
Description
Description
RepoBar crashes when repositories with duplicate keys are present in the data pipeline. This manifests as two different crash types:
Crash 1: Dictionary Assertion Failure
Crashes immediately on launch with an assertion failure in Dictionary(uniqueKeysWithValues:).
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Thread 0 Crashed - _assertionFailure(_:_:file:line:flags:)
Stack trace:
0 libswiftCore.dylib _assertionFailure
1 RepoBar specialized _NativeDictionary.merge<A>(_:isUnique:uniquingKeysWith:)
2 RepoBar specialized AppState.mergeHydrated(_:into:)
3 RepoBar AppState.refresh()
4 RepoBar closure #1 in AppState.requestRefresh(cancelInFlight:)
Crash 2: NSMenu Item Already Attached
Crashes when opening the menu with an NSMenu assertion failure.
*** Assertion failure in <private>, NSMenu.m:1360
NSMenu: Exception raised while opening the menu: Item to be inserted into menu already is in another menu
*** Inconsistent state. A menu item's height should never be 0.
This occurs because the same cached NSMenuItem is returned for duplicate repos and added to the menu twice.
Root Cause
Both crashes share the same root cause: duplicate repositories appearing in the data pipeline. This can occur when:
- Pinned repositories have case variations of the same repo name
- The GitHub API returns the same repository via different code paths during hydration
- Repository list contains duplicates before filtering
Affected Code
Dictionary crash - AppState+Refresh.swift:
private func mergeHydrated(_ detailed: [Repository], into repos: [Repository]) -> [Repository] {
let lookup = Dictionary(uniqueKeysWithValues: detailed.map { ($0.fullName, $0) })
// crashes when duplicate fullName keys exist
}Menu crash - StatusBarMenuBuilder.swift:
for (index, repo) in repos.enumerated() {
let item = self.repoMenuItem(for: repo, isPinned: isPinned)
items.append(item) // same cached item added twice if duplicates exist
}Environment
- RepoBar version: 0.2.0
- macOS: 26.2 (25C56)
- Hardware: Mac16,12 (ARM64)
- User has pinned repositories configured
Proposed Fix
Dictionary fix
Replace Dictionary(uniqueKeysWithValues:) with Dictionary(_:uniquingKeysWith:) which gracefully handles duplicate keys:
let lookup = Dictionary(detailed.map { ($0.fullName, $0) }, uniquingKeysWith: { first, _ in first })Menu fix
Deduplicate repos by id before building menu items:
var usedRepoKeys: Set<String> = []
let uniqueRepos = repos.filter { repo in
if usedRepoKeys.contains(repo.id) { return false }
usedRepoKeys.insert(repo.id)
return true
}