Freika/dawarich · warning
Failed to load scratch layer:
Error message
Failed to load scratch layer:
What it means
The scratch layer (freehand drawing on the map) is code-split and loaded on demand through lazyLoader.loadLayer('scratch') when settings.scratchEnabled is on. This warning means the dynamic import or the layer's constructor/add() threw: most often a chunk load error after a new deploy invalidated old asset hashes, otherwise a runtime bug in the ScratchLayer module itself.
Source
Thrown at app/javascript/controllers/maps/maplibre/layer_manager.js:297
)
}
// Private methods for individual layer management
async _addScratchLayer(pointsGeoJSON) {
try {
if (!this.layers.scratchLayer && this.settings.scratchEnabled) {
const ScratchLayer = await lazyLoader.loadLayer("scratch")
this.layers.scratchLayer = new ScratchLayer(this.map, {
visible: true,
apiClient: this.api,
})
await this.layers.scratchLayer.add(pointsGeoJSON)
} else if (this.layers.scratchLayer) {
await this.layers.scratchLayer.update(pointsGeoJSON)
}
} catch (error) {
console.warn("Failed to load scratch layer:", error)
}
}
_addHeatmapLayer(pointsGeoJSON) {
if (!this.layers.heatmapLayer) {
this.layers.heatmapLayer = new HeatmapLayer(this.map, {
visible:
this.settings.heatmapEnabled &&
!tiledPointsActive(SettingsManager.getSettings()),
})
this.layers.heatmapLayer.add(pointsGeoJSON)
} else {
this.layers.heatmapLayer.update(pointsGeoJSON)
}
}
_addHexagonLayer() {
if (this.layers.hexagonsLayer) return this.layers.hexagonsLayerView on GitHub (pinned to 97fad417c5)
Solutions
- Hard-reload the page (Cmd/Ctrl+Shift+R) — stale chunk references after a deploy are the most common cause
- Verify the scratch chunk exists in the current build output and matches the asset manifest
- If the chunk loads but still throws, reproduce with the error object expanded to find the failing line in ScratchLayer
- If the feature is not ready, disable scratchEnabled in settings until the build is fixed
Example fix
// before
const ScratchLayer = await lazyLoader.loadLayer("scratch")
// after
let ScratchLayer
try {
ScratchLayer = await lazyLoader.loadLayer("scratch")
} catch (e) {
if (String(e?.name).includes("ChunkLoadError")) {
window.location.reload() // pick up freshly deployed chunk names
return
}
throw e
} Defensive patterns
Strategy: retry
Validate before calling
if (!this.settings.scratchEnabled) return // never import when the feature is off
Try / catch
try {
const ScratchLayer = await lazyLoader.loadLayer("scratch")
this.layers.scratchLayer = new ScratchLayer(this.map, { visible: true, apiClient: this.api })
await this.layers.scratchLayer.add(pointsGeoJSON)
} catch (error) {
if (String(error?.name).includes("ChunkLoadError")) {
window.location.reload() // one reload picks up new chunk hashes after a deploy
return
}
console.warn("Failed to load scratch layer:", error)
} Prevention
- Prompt a reload when lazy chunks 404 after a deploy instead of silently dropping the feature
- Gate optional layers behind their settings flag so the import is never attempted unnecessarily
- Keep lazy-loaded modules self-contained so their absence degrades only their own feature
When it happens
Trigger: A long-lived tab loading the scratch chunk after a deploy renamed chunk files (ChunkLoadError); a Vite/bundler misconfiguration dropping the scratch chunk from the build; an exception inside new ScratchLayer(...) or scratchLayer.add(pointsGeoJSON); scratchEnabled turned on on a build that lacks the layer code.
Common situations: Deploying while users have the map open; stale service-worker or CDN caches serving mixed asset versions; feature flag enabled before the code shipped; partial local builds during development.
Related errors
- Could not classify zip contents -- file may be corrupted
- [EventHandlers] Failed to highlight track:
- Failed to parse track segments:
- Failed to parse track segments for marker update:
- Failed to add photos layer:
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/ed7bb8e2b578f849.
Report an issue: GitHub.