Skip to content

Mapbox GL Draw crashes on **MapLibre** GL JS v5 mobile. #1497

@WhaleFell

Description

@WhaleFell

due to third-argument map.on options being misinterpreted as layerIds

Environment

MapLibre GL JS v5.x (MapLibre)
@mapbox/mapbox-gl-draw v1.4.0
Mobile/touch devices (touchstart events)

Observed error

Uncaught TypeError: t2.filter is not a function
    at Map._createDelegatedListener (map.ts:1445)
    at Map.fire (evented.ts:132)
    at ...
    at MapEventHandler.touchstart (map_event.ts:70)

Root cause analysis

On touch devices, Mapbox GL Draw registers events like:

map.on('touchstart', handler, { passive: true })

MapLibre GL JS v5 Map#on does not support a third options argument. { passive: true }
ref: MapLibre on API

The third argument is mis-parsed, so layerIds becomes the handler function instead of an array.
In MapLibre’s _createDelegatedListener, it executes layerIds.filter(...), causing filter is not a function.

Why it only happens on mobile

The offending path is triggered by touch events (touchstart, etc.), which are used only on mobile devices.
Workaround (for MapLibre users)

Patch map.on to ignore the 3rd argument when the 2nd argument is the listener function, or modify Draw’s event registration to not pass { passive: true } with MapLibre.

Suggested fix in Draw

Detect MapLibre (or check for map.on signature) and avoid passing third argument options:
map.on('touchstart', handler) instead of map.on('touchstart', handler, { passive: true }).

Temporary fix

  private patchMapEventOptions(map: maplibregl.Map): maplibregl.Map {
    // Normalize map.on signature to tolerate third-arg options from Mapbox Draw.
    const originalOn = map.on.bind(map)
    map.on = ((type: string, layerIds: unknown, listener?: unknown) => {
      if (typeof layerIds === 'function' && listener && typeof listener === 'object') {
        // @ts-expect-error hackly used
        return originalOn(type, layerIds)
      }
      // @ts-expect-error hackly used
      return originalOn(type, layerIds as string | string[], listener as maplibregl.Listener)
    }) as maplibregl.Map['on']

    return map
  }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions