Skip to content

Conversation

@ggfevans
Copy link

@ggfevans ggfevans commented Jan 31, 2026

Summary

  • Replace Dictionary(uniqueKeysWithValues:) with Dictionary(_:uniquingKeysWith:) to prevent crashes when duplicate fullName keys occur
  • Apply fix to all three locations in AppState+Refresh.swift that use this pattern
  • New: Deduplicate repos by id in menu builder to prevent NSMenu crashes when cached items are added twice

Problem

The app crashes in two ways when duplicate repositories appear in the data:

  1. Dictionary crash: EXC_BREAKPOINT (SIGTRAP) in _assertionFailure from _NativeDictionary.merge when mergeHydrated encounters repositories with duplicate fullName values
  2. Menu crash: NSMenu assertion failure "Item to be inserted into menu already is in another menu" when the same cached NSMenuItem is added to the menu twice

Root Cause

Duplicate repository keys can occur when:

  1. Pinned repositories have case variations
  2. Same repo is returned via different code paths during hydration
  3. Repository list contains duplicates before filtering

Solution

Dictionary fix

Use Dictionary(_:uniquingKeysWith:) which gracefully handles duplicates by keeping the first occurrence:

// Before (crashes on duplicates):
let lookup = Dictionary(uniqueKeysWithValues: detailed.map { ($0.fullName, $0) })

// After (handles duplicates):
let lookup = Dictionary(detailed.map { ($0.fullName, $0) }, uniquingKeysWith: { first, _ in first })

Menu fix

Deduplicate repos by id before iterating to build menu items:

// Deduplicate repos by id to prevent adding the same cached menu item twice
var usedRepoKeys: Set<String> = []
let uniqueRepos = repos.filter { repo in
    if usedRepoKeys.contains(repo.id) { return false }
    usedRepoKeys.insert(repo.id)
    return true
}

Test plan

  • Build succeeds (swift build)
  • App launches without crash with pinned repositories configured
  • Existing tests pass (one unrelated network timeout in LoopbackServerTests)
  • Menu opens without assertion errors

Fixes #31

🤖 Generated with Claude Code

Replace `Dictionary(uniqueKeysWithValues:)` with
`Dictionary(_:uniquingKeysWith:)` to gracefully handle duplicate
`fullName` keys that can occur with pinned repositories.

Fixes steipete#31

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ggfevans ggfevans marked this pull request as draft January 31, 2026 00:25
When the repos array contains duplicate entries with the same id,
the cached NSMenuItem would be returned twice and added to the menu
twice. The second addItem fails with "Item to be inserted into menu
already is in another menu" because the item is already in the menu.

Fix by deduplicating repos by id before iterating. This uses the
existing usedRepoKeys set but populates it BEFORE processing items
rather than after.

Root cause: same as the dictionary crash - duplicate repositories can
appear in the pipeline when the same repo is both fetched from the API
and present in the pinned list.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ggfevans ggfevans changed the title fix: handle duplicate repository keys in Dictionary initialization fix: handle duplicate repository keys in Dictionary and NSMenu Jan 31, 2026
@ggfevans ggfevans marked this pull request as ready for review January 31, 2026 01:55
@ggfevans
Copy link
Author

heads up @steipete - low hanging fruit

Keep the most recently fetched repository data when duplicates exist,
rather than the first occurrence. Also fix the same crash pattern in
the iOS target's mergeHydrated.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

App crashes with duplicate repository keys (Dictionary and NSMenu)

1 participant