{"record":{"id":"f8029060bdabc990","repo":"Freika/dawarich","slug":"maps-v2-visits-layer-not-found-cannot-update","errorCode":null,"errorMessage":"[Maps V2] Visits layer not found, cannot update","messagePattern":"\\[Maps V2\\] Visits layer not found, cannot update","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/javascript/controllers/maps/maplibre/visits_manager.js","lineNumber":409,"sourceCode":"\n    if (controller) {\n      controller.open(lat, lng, this.controller)\n    } else {\n      Toast.error(translate(\"messages.visit_creation_controller_not_available\"))\n    }\n  }\n\n  /**\n   * Handle visit creation event - reload visits, update layer, and\n   * enable the Visits layer so the new visit is immediately visible.\n   * Without auto-enabling, users would create a visit and see nothing\n   * on the map because the layer toggle was off.\n   */\n  async handleVisitCreated(event) {\n    try {\n      const visitsLayer = this.layerManager.getLayer(\"visits\")\n      if (!visitsLayer) {\n        console.warn(\"[Maps V2] Visits layer not found, cannot update\")\n        return\n      }\n\n      const visit = event?.detail?.visit\n      let visits\n      if (visit && this.filterManager.allVisits?.length) {\n        // Layer already populated — append/replace this visit locally instead\n        // of re-pulling the whole viewport from the backend.\n        visits = this._upsertVisit(this.filterManager.allVisits, visit)\n      } else {\n        // Initial load: fetch the viewport set once, then make sure the\n        // just-saved visit is included even if it falls outside the current\n        // date range or viewport bounds (otherwise its marker never appears).\n        const fetched = await this.fetchVisitsForCurrentViewport()\n        visits = visit ? this._upsertVisit(fetched, visit) : fetched\n      }\n\n      this.filterManager.setAllVisits(visits)","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/javascript/controllers/maps/maplibre/visits_manager.js#L391-L427","documentation":"When a visit creation event arrives, VisitsManager upserts the saved visit into the 'visits' layer (or fetches the viewport set on first load) and auto-enables the layer so the new visit is immediately visible. If LayerManager has no 'visits' layer registered, it warns and returns, so the just-created visit will not appear on the map until reload.","triggerScenarios":"A visit saved before the map finished adding layers; the document-level event reaching a page whose map was torn down by Turbo navigation while the listener survived; the visits layer disabled or renamed; the event broadcast from another browser tab whose map lacks the layer.","commonSituations":"Multi-tab workflows; Turbo cache restores where managers outlive their layers; races between initial layer setup and a quick visit save; layer id changes during refactors.","solutions":["Confirm timing: if the event fires during map init, queue it and replay once addLayers completes","Unsubscribe document-level listeners in the manager's disconnect/destroy lifecycle","Verify the layer id string matches what LayerManager registers ('visits')","If the visits layer is intentionally off, downgrade to debug logging"],"exampleFix":"// before\nconst visitsLayer = this.layerManager.getLayer(\"visits\")\nif (!visitsLayer) {\n  console.warn(\"[Maps V2] Visits layer not found, cannot update\")\n  return\n}\n// after\nconst visitsLayer = this.layerManager.getLayer(\"visits\")\nif (!visitsLayer) {\n  if (this.layersReady) console.warn(\"[Maps V2] Visits layer not found, cannot update\")\n  else this.pendingVisitEvents.push(event) // replay after layers initialize\n  return\n}","handlingStrategy":"type-guard","validationCode":"const visitsLayer = this.layerManager?.getLayer(\"visits\")\nif (!visitsLayer || typeof visitsLayer.setData !== \"function\") {\n  if (this.layersReady) console.warn(\"[Maps V2] Visits layer not found, cannot update\")\n  else this.pendingVisitEvents.push(event) // replay after addLayers\n  return\n}","typeGuard":"/** @param {unknown} layer @returns {boolean} */\nfunction isVisitsLayer(layer) {\n  return Boolean(\n    layer &&\n    typeof layer === \"object\" &&\n    typeof layer.setData === \"function\"\n  )\n}","tryCatchPattern":"try {\n  await this._reloadVisits(visitsLayer)\n} catch (error) {\n  console.warn(\"[Maps V2] Visits reload failed:\", error)\n}","preventionTips":["Bind document-level visit events only after layers finish initializing; unbind on disconnect","Queue early events and replay them once the layer exists","Keep layer id constants in one module so registrations and lookups cannot drift"],"tags":["dawarich","visits-layer","event-race","stimulus","turbo"],"backgroundTag":"map-layer-not-found","analyzedSha":"97fad417c5a11b0eb11157890635e015723a2e97","analyzedAt":"2026-08-21T17:04:17.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}