mapbox / mapbox/mapbox-maps-ios
Crash - Duplicate keys of type 'AnyHashable' were found in a Dictionary.
Nobody has claimed this yet.
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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