Freika/dawarich · warning
[TracksLayer] Animation frame error:
Error message
[TracksLayer] Animation frame error:
What it means
TracksLayer animates a flowing line-gradient by calling map.setPaintProperty on every requestAnimationFrame while animationActive is true. If the flow layer disappears between frames — toggled off, style changed, map destroyed — setPaintProperty throws and each failing frame logs this warning while the loop keeps running (and keeps logging) until stopped.
Source
Thrown at app/javascript/maps_maplibre/layers/tracks_layer.js:297
? Math.max(
4,
Math.min(30, Math.round(this.selectedTrackLength / 400)),
)
: 6
// Transparent base when segments visible so their colors show through
const baseColor = this.segmentsActive
? "rgba(255,255,255,0)"
: undefined
this.map.setPaintProperty(
this.flowLayerId,
"line-gradient",
this._buildFlowGradient(phase, { baseColor, numDashes }),
)
}
} catch (e) {
console.warn("[TracksLayer] Animation frame error:", e)
}
if (this.animationActive) {
this.animationFrame = requestAnimationFrame(animate)
}
}
this.animationFrame = requestAnimationFrame(animate)
}
/**
* Stop the flowing gradient animation
*/
_stopFlowAnimation() {
this.animationActive = false
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame)
this.animationFrame = nullView on GitHub (pinned to 97fad417c5)
Solutions
- Stop the flow animation (cancel the rAF and clear animationActive) in the same code path that removes or hides the flow layer
- Guard each frame with this.map.getLayer(this.flowLayerId) before setPaintProperty
- In remove()/disconnect(), stop the animation and null this.animationFrame
- Include a map-alive check (e.g. !this.map._removed) in the loop condition
Example fix
// before
this.map.setPaintProperty(this.flowLayerId, "line-gradient", gradient)
// after
if (this.animationActive && !this.map._removed && this.map.getLayer(this.flowLayerId)) {
this.map.setPaintProperty(this.flowLayerId, "line-gradient", gradient)
} else {
this.stopFlowAnimation()
return
} Defensive patterns
Strategy: type-guard
Validate before calling
const flowLayerExists =
this.animationActive &&
this.map &&
!this.map._removed &&
typeof this.map.getLayer === "function" &&
this.map.getLayer(this.flowLayerId) !== undefined
if (!flowLayerExists) {
this.stopFlowAnimation()
return
} Type guard
/** @param {object} map @param {string} layerId @returns {boolean} */
function hasLayer(map, layerId) {
return Boolean(
map &&
!map._removed &&
typeof map.getLayer === "function" &&
map.getLayer(layerId)
)
} Try / catch
try {
this.map.setPaintProperty(this.flowLayerId, "line-gradient", gradient)
} catch (e) {
console.warn("[TracksLayer] Animation frame error:", e)
this.stopFlowAnimation() // stop the loop instead of logging every frame
} Prevention
- Pair every requestAnimationFrame loop with a cancellation path that runs on layer removal and map teardown
- Check map.getLayer before any per-frame paint property call
- Stop animations in the layer's remove()/disconnect lifecycle, not only on user toggle
When it happens
Trigger: Toggling the tracks layer or segments mode off without stopping the flow animation; changing the base style which removes custom layers; Turbo navigation destroying the map mid-animation; a bad phase/numDashes value producing an invalid line-gradient expression that MapLibre rejects.
Common situations: Users switching layers while a track animation plays; style hot-swaps; long sessions where an animating track's layer is later removed; rapid toggling of the flowing-tracks setting.
Related errors
- [EventHandlers] Failed to highlight track:
- Failed to fetch points: ${response.statusText}
- Invalid tile coordinates
- Failed to add photos layer:
- [MapInitializer] No features to fit bounds to
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/f44fd23556ddbc7b.
Report an issue: GitHub.