mapbox / mapbox/mapbox-maps-ios

Crash - Duplicate keys of type 'AnyHashable' were found in a Dictionary.

Open
#2,282 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auto-triaged bug :beetle:
Dominant language
Swift
Stars
601
Forks
196
PR merge metrics
No merged PRs in 30d

Description

## Environment

- Xcode version: Version 16.2 (16C5032a)
- iOS version: iOS 18.2.1 (22C161)
- Devices affected: all
- Maps SDK Version: 11.9.0 (and possibly 11.8.0)

## Observed behavior and steps to reproduce

Crash with: ' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion. > Fatal error

Happens randomly during View update, various devices, could not yet be observed in debug
Affects stability of the app

## Expected behavior

No crash

## Notes / preliminary analysis

in final class AnnotationManagerImpl: AnnotationManagerImplProtocol {

func set(newAnnotations: [(AnyHashable, AnnotationType)]) {
var resolvedAnnotations = [AnnotationType]()
newAnnotations.forEach { elementId, annotation in
var annotation = annotation
let stringId = idsMap[elementId] ?? annotation.id
idsMap[elementId] = stringId

Duplicate keys of type 'AnyHashable' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion.
po idsMap shows:
Simultaneous accesses to 0x158d4cfd0, but modification requires exclusive access.
Previous access (a modification) started at closure #1 in AnnotationManagerImpl.set(newAnnotations:) + 3120 (0x10b108460).

annotation.id = stringId
annotation.isDraggable = false
annotation.isSelected = false
resolvedAnnotations.append(annotation)
}
// TODO: evict old ids
annotations = resolvedAnnotations
}

Sentry Thread Stack Trace
```
ibswiftCore +0x01172c
_assertionFailure(_: StaticString, _: String, flags: UInt32
libswiftCore +0x198624
KEY_TYPE_OF_DICTIONARY_VIOLATES_HASHABLE_REQUIREMENTS(Any.Type)
+0x60ac70
specialized _NativeDictionary.mutatingFind(_: A, isUnique: Bool) ()
+0x2dd60c
specialized _NativeDictionary.setValue(_: __owned B, forKey: A, isUnique: Bool) ()
+0x2dd60c
specialized Dictionary._Variant.setValue(_: __owned B, forKey: A) ()
+0x2c78f4
specialized Dictionary.subscript.setter ()
+0x2c78f4
**closure #1 (AnyHashable, A) in AnnotationManagerImpl.set(newAnnotations: [(AnyHashable, A)]) (AnnotationManagerImpl.swift:211)**
+0x2caa74
thunk for @callee_guaranteed (@in_guaranteed AnyHashable, @in_guaranteed A) -> () ()
libswiftCore +0x0f4c9c
Sequence.forEach((A.Element))
+0x2c779c
**AnnotationManagerImpl.set(newAnnotations: [(AnyHashable, A)]) (AnnotationManagerImpl.swift:208)**
+0x346c68
MountedAnnotationGroup.update(manager: A, context: MapContentNodeContext) (MountedAnnotationGroup.swift:61)
+0x347048
MountedAnnotationGroup.tryUpdate(from: MapContentMountedComponent, with: MapContentNodeContext) (MountedAnnotationGroup.swift:52)
+0x3471bc
protocol witness for MapContentMountedComponent.tryUpdate(from: MapContentMountedComponent, with: MapContentNodeContext) in conformance MountedAnnotationGroup ()
+0x359928
MapContentNode.update
(with: A) (MapContentNode.swift:97)
+0x330c50
MapContent.update(MapContentNode) (MapContent.swift:93)
+0x330ac0
$s10MapboxMaps15TupleMapContentVyACyqd__qd__Qp_tGqd__qd__QpcRvd__qd__qd__Qp_tRszAA0dE0Rd__lufcyAA0dE4NodeCcfU_yAGyXEXEfU_ (MapContent.swift:24)
+0x3308d8
MapContentNode.withChildrenNodes((())) (MapContentNode.swift:42)
+0x3308d8
$s10MapboxMaps15TupleMapContentVyACyqd__qd__Qp_tGqd__qd__QpcRvd__qd__qd__Qp_tRszAA0dE0Rd__lufcyAA0dE4NodeCcfU_ (MapContent.swift:23)
+0x1f067c
specialized thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> () ()
+0x359850
MapContentNode.update
(with: A) (MapContentNode.swift:82)
+0x330c50
MapContent.update(MapContentNode) (MapContent.swift:93)
+0x3312d8
closure #1 (()) in OptionalMapContent.visit(MapContentNode) (MapContent.swift:79)
+0x331190
MapContentNode.withChildrenNodes((())) (MapContentNode.swift:42)
+0x331190
OptionalMapContent.visit(MapContentNode) (MapContent.swift:77)
+0x359850
MapContentNode.update
(with: A) (MapContentNode.swift:82)
+0x330c50
MapContent.update(MapContentNode) (MapContent.swift:93)
+0x330ac0
$s10MapboxMaps15TupleMapContentVyACyqd__qd__Qp_tGqd__qd__QpcRvd__qd__qd__Qp_tRszAA0dE0Rd__lufcyAA0dE4NodeCcfU_yAGyXEXEfU_ (MapContent.swift:24)
+0x3308d8
MapContentNode.withChildrenNodes((())) (MapContentNode.swift:42)
+0x3308d8
$s10MapboxMaps15TupleMapContentVyACyqd__qd__Qp_tGqd__qd__QpcRvd__qd__qd__Qp_tRszAA0dE0Rd__lufcyAA0dE4NodeCcfU_ (MapContent.swift:23)
+0x1f067c
specialized thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> () ()
+0x359850
MapContentNode.update
(with: A) (MapContentNode.swift:82)
+0x330c50
MapContent.update(MapContentNode) (MapContent.swift:93)
+0x35d26c
MapContentNodeContext.update(mapContent: MapContent, root: MapContentNode) (MapContentReconciler.swift:75)
+0x35ca48
MapContentReconciler.update(with: MapContent) (MapContentReconciler.swift:47)
+0x64aa68
MapContentReconciler.content.didset (MapContentReconciler.swift:8)
+0x64aa68
MapContentReconciler.content.setter (MapContentReconciler.swift)
+0x64aa68
StyleManager.setMapContent(()) (StyleManager.swift:461)
+0x68de68
MapBasicCoordinator.update(viewport: ConstantOrBinding, deps: MapDependencies, layoutDirection: LayoutDirection, animationData: ViewportAnimationData?) (MapBasicCoordinator.swift:91)
+0x689044
Map.updateUIViewController(_: UIViewController, context: UIViewControllerRepresentableContext) (Map.swift:143)
```
## Additional links and references

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with AnnotationManagerImpl.swift lines 208-211, especially set(newAnnotations:), and compare the reported Dictionary crash and simultaneous-access trace with the surrounding annotation update flow. The change is complete when the duplicate-key or exclusivity crash no longer occurs during view updates across the affected iOS and Maps SDK versions.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, swift
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.