{"record":{"id":"e2b66392cf5efa46","repo":"Freika/dawarich","slug":"failed-to-parse-track-segments","errorCode":null,"errorMessage":"Failed to parse track segments:","messagePattern":"Failed to parse track segments:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/javascript/controllers/maps/maplibre/event_handlers.js","lineNumber":714,"sourceCode":"  /**\n   * Load track segments from API (lazy loading)\n   * @private\n   */\n  async _loadTrackSegments(trackId, fullFeature) {\n    try {\n      const trackFeature =\n        await this.controller.api.fetchTrackWithSegments(trackId)\n      if (!trackFeature) return\n\n      let segments = []\n      try {\n        const props = trackFeature.properties\n        segments =\n          typeof props.segments === \"string\"\n            ? JSON.parse(props.segments)\n            : props.segments || []\n      } catch (err) {\n        console.warn(\"Failed to parse track segments:\", err)\n      }\n\n      const tracksLayer = this.controller.layerManager.getLayer(\"tracks\")\n      if (tracksLayer?.showSegments) {\n        tracksLayer.showSegments(fullFeature, segments)\n        tracksLayer.setSegmentHoverCallback((segmentIndex) => {\n          this._highlightSegmentOnMap(segmentIndex)\n          this._dispatchSegmentHover(trackId, segments[segmentIndex]?.id)\n        })\n        tracksLayer.setSegmentLeaveCallback(() => {\n          this._clearSegmentHighlight()\n          this._dispatchSegmentUnhover(trackId)\n        })\n      }\n\n      this._createTrackSegmentMarkers(trackId, fullFeature, segments)\n    } catch (error) {\n      console.error(\"Failed to load track segments:\", error)","sourceCodeStart":696,"sourceCodeEnd":732,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/javascript/controllers/maps/maplibre/event_handlers.js#L696-L732","documentation":"When a track is clicked, the handler fetches the full track with segments and expects properties.segments to be either an already-parsed array or a JSON string. If it is a string, JSON.parse() runs inside a try/catch; malformed or truncated JSON throws and logs this warning. segments stays [] so the track still renders, but per-segment colors and hover callbacks show nothing.","triggerScenarios":"The tracks serializer emitting invalid JSON in properties.segments (truncated by a response size limit, double-encoded string, NaN serialized by to_json); a backend change wrapping segments in a new shape so the parsed value is not an array; very large segment arrays clipped by a proxy or cache.","commonSituations":"Long tracks with thousands of points where serialized segments exceed response limits; serializer refactors switching between string and array; caching layers that re-encode JSON; hand-written fixtures with malformed segment strings.","solutions":["Log props.segments (typeof plus first 200 chars) to see whether it is malformed, double-encoded, or an unexpected shape","Fix the backend serializer to emit valid JSON or a native array — arrays avoid the parse entirely","Validate the parsed value is an array before using it: Array.isArray(segments) ? segments : []","Add a serializer regression test covering a track with many segments"],"exampleFix":"// before\nsegments =\n  typeof props.segments === \"string\"\n    ? JSON.parse(props.segments)\n    : props.segments || []\n// after\nif (typeof props.segments === \"string\") {\n  try {\n    const parsed = JSON.parse(props.segments)\n    segments = Array.isArray(parsed) ? parsed : []\n  } catch (err) {\n    console.warn(\"Failed to parse track segments:\", err)\n    segments = []\n  }\n} else {\n  segments = Array.isArray(props.segments) ? props.segments : []\n}","handlingStrategy":"try-catch","validationCode":"function safeParseSegments(raw) {\n  if (Array.isArray(raw)) return raw\n  if (typeof raw !== \"string\" || raw.length === 0) return []\n  try {\n    const parsed = JSON.parse(raw)\n    return Array.isArray(parsed) ? parsed : []\n  } catch {\n    return []\n  }\n}\nconst segments = safeParseSegments(props.segments)","typeGuard":"/** @param {unknown} value @returns {value is Array} */\nfunction isSegmentArray(value) {\n  return Array.isArray(value)\n}","tryCatchPattern":"try {\n  segments = safeParseSegments(props.segments)\n} catch (err) {\n  console.warn(\"Failed to parse track segments:\", err)\n  segments = [] // degrade to no-segment rendering, keep the track visible\n}","preventionTips":["Prefer server-side arrays over JSON strings in GeoJSON properties when payload size allows","Centralize segment parsing in one shared helper instead of repeating JSON.parse at each call site","Assert the parsed result is an array, not merely that JSON.parse succeeded"],"tags":["json-parse","dawarich","track-segments","geojson","api-client"],"backgroundTag":"json-parse-error","analyzedSha":"97fad417c5a11b0eb11157890635e015723a2e97","analyzedAt":"2026-08-21T17:04:17.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}