Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Data-driven `line-dasharray` of `[]` leaves lines undrawn in some tiles (LineAtlas key changes after `addDash` mutates the array)

Open
#13,739 0 comments 0 reactions 0 assignees View on GitHub

@pchukwuemeka424 is already working on this.

Since Oct 26, 2026.

  • #13745 by @pchukwuemeka424 — open

Assessment

Difficulty
3/5
Estimated time
Half a day
Newbie friendliness
62/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript

Research direction

Start in src/render/line_atlas.ts at LineAtlas#addDash and getKey, where the empty dasharray is mutated in place, then in src/data/bucket/line_bucket.ts at addFeatureDashes, where the key is recomputed from that mutated array. Run the repro page with showTileBoundaries on and check that every tile's lineAtlas.positions holds one key for [] and no "1round" key. Done means the [] case gets a single consistent key, the caller's array is left unmodified, and all ten lines draw in every tile.

Written by the indexing model from the issue text.

Description

auto-triaged bug :lady_beetle:
mapbox-gl-js version

3.32.0

Browser and version

Chrome (macOS)

Expected behavior
  1. Add a GeoJSON source with line features whose dash property is an empty array [] (a solid line).
  2. Add a line layer with 'line-cap': 'round' and a data-driven 'line-dasharray': ['get', 'dash'].
  3. View the lines at zoom 14+ with showTileBoundaries on.

Expected: Every line is drawn as a solid line across all tiles. LineAtlas#addDash says an empty dasharray "draws a full line", and the style spec doesn't forbid an empty array.

Actual behavior

Some lines are missing within individual tiles: the stroke stops and starts exactly at tile boundaries. Which lines and tiles are affected changes after zooming or calling setData. No warning or error is logged. Using [1, 0] (or leaving line-dasharray out) draws every line fully.

The repro page with tile boundaries shown: the bottom line is drawn up to the edge of tile 14/2650/5412, missing across that whole tile, and drawn again after it. The other lines cross the same tile normally.

Image
Cause

LineAtlas#addDash builds the cache key from the array, then mutates the caller's array in place when it's empty (line_atlas.ts#L163-L180):

const key = this.getKey(dasharray, lineCap);        // [] -> "round"
if (this.positions[key]) return this.positions[key];
...
if (dasharray.length === 0) {
    dasharray.push(1);                              // caller's array is now [1]
}
...
this.positions[key] = pos;                          // stored under "round"

LineBucket#addFeatureDashes then computes the key again from the same, now mutated, array (line_bucket.ts#L508-L511):

lineAtlas.addDash(dashArray, cap);
feature.patterns[layer.id] = [lineAtlas.getKey(dashArray, cap)];  // "1round", not in positions

So in each tile, the first feature with an unmutated [] is stored under "round" but looked up under "1round". That lookup finds nothing, so the feature gets no dash position in that tile and isn't drawn there. Later features in the same tile hit the cached "round" entry before the mutation, so they're fine.

The mutated array is the feature's own property value, shared across that worker's tiles. So the next tile sees [1], and the failure moves around depending on tile processing order. That's why the affected lines vary and change on zoom.

The new assert on main (line_bucket.ts#L718, "Dash key ... has no LineAtlas position") should fire for this case in dev builds.

Checking the loaded tiles confirms it: with [], the tiles' lineAtlas.positions hold "round" and, in some tiles, "1round". A "1round" key can only exist because the worker mutated a feature's array. With [1, 0], every tile holds only "1,0round".

Possible fix

Normalize without mutating the input, and use one key for both storing and looking up. For example, in addDash:

if (dasharray.length === 0) dasharray = [1];
const key = this.getKey(dasharray, lineCap);

and have addFeatureDashes use a key returned by addDash, or normalize the same way before calling getKey. It would also help to warnOnce if an empty dasharray is ever treated differently from a solid line.

Workaround

Use [1, 0] instead of [] for solid lines, or don't set line-dasharray on features that should be solid.

Link to the demonstration

No response

Steps to trigger the unexpected behavior
<script src="https://api.mapbox.com/mapbox-gl-js/v3.32.0/mapbox-gl.js"></script> <style> body { margin: 0 }
    #map {
        width: 100vw;
        height: 100vh
    }
</style>
<script> // No Mapbox-hosted data is used, so the page renders without a valid token mapboxgl.accessToken = '';
    // Ten straight lines, each with its own empty `dash` array (solid line).
    // Change `[]` to `[1, 0]` and every line renders fully.
    const center = [-121.758798, 51.994982];
    const features = [];
    for (let i = 0; i < 10; i++) {
        const lat = center[1] - 0.005 + i * 0.001;
        features.push({
            type: 'Feature',
            properties: { dash: [] },
            geometry: { type: 'LineString', coordinates: [[center[0] - 0.05, lat], [center[0] + 0.05, lat + 0.001]] },
        });
    }

    const map = new mapboxgl.Map({
        container: 'map',
        style: { version: 8, sources: {}, layers: [{ id: 'bg', type: 'background', paint: { 'background-color': '#ffffff' } }] },
        center,
        zoom: 14.5,
    });
    map.showTileBoundaries = true;

    map.on('load', () => {
        map.addSource('lines', { type: 'geojson', data: { type: 'FeatureCollection', features } });
        map.addLayer({
            id: 'lines',
            type: 'line',
            source: 'lines',
            layout: { 'line-cap': 'round', 'line-join': 'round' },
            paint: { 'line-color': '#ff0000', 'line-width': 4, 'line-dasharray': ['get', 'dash'] },
        });
    });
</script>
Relevant log output

Dominant language
TypeScript
Stars
12.5k
Forks
2.4k
PR merge metrics
No merged PRs in 30d

Getting set up

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.

More from mapbox/mapbox-gl-js

All issues in mapbox/mapbox-gl-js

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.